Artemis | Blog | About & Contact

2020 / 03 / 17 (raw)

Notes on auth token persistence

In a "traditional" website, authentication is usually handled through sessions, a session being a temporary server-side stockage associated to a cookie identifying the session.

For example, by default in PHP, the PHPSESSID cookie contains a "random" string that identifies a server-side object containing the user's session details.

But with the hype around JWTs and the "stateless" craze, we're seeing a worrying, unsecure trend.

We're seeing the following habit:

const token = localStorage.getItem('auth-token');
fetch('/api/super-secure-data', {
    headers: {
        'Authorization': `Bearer ${token}`,
    },
});

So, what issue can we see here?

But, what solution does exist?

Well, cookies.

Both XMLHttpRequest and fetch automatically support cookie passing, so you won't have to handle tokens yourself.

Note that for fetch, there is a setting to set.

"But, there's a lot of topics on how to access cookies from Javascript. How is it any better?"

Cookies, like most things in IT, has some flags that can be enabled to instruct the browser to handle them differently.

Two of them are interesting here.

Additionally, the Secure attribute will force cookies to only work over HTTPS.

That means that sending an Ajax request to another domain, the cookies won't be transfered no matter what happens.

That also means that, since you don't see them, a malicious code will also not be able to access them, so no auth data extraction!

fetch('/api/super-secure-data', {
    init: {
        credentials: 'same-origin',
    },
});

But, what if I interact with an authenticated API service which doesn't use cookies and requires me to use something less secure, such as an Authorization header?

The thing, with those rules, is that it only applies to the browser.

You can (and probably should) set up a proxy that will transparently convert the defined cookie to an Authorization header.

Most HTTP reverse proxies, such as Apache, NGINX, Caddy, Traefik, and such, are able to do such a job for you, with little configuration.

Additional steps

If you want some more fine-grained control over which network feature is or isn't allowed, you should definitely take a look at the Content-Security-Policy header.

This will allow you, for example, to specify sources you want to allow for media resources (such as images or videos).