When it comes to authenticating your web app, there are two main choices - session auth and token auth.
There are many different kinds of token auth, but JWT is a popular format.
When a user logs in, we provide them with a JSON payload, which can contain any information we want, such as a user_id, permissions, favourite colour of car etc. This payload is signed using a secret key, so when the user presents this token to us (for example, in an API request), we can verify it hasn't been tampered with.
This is often given as an advantage of JWT. In theory, since all the information is embedded within the token itself, there's no need to do database calls, like with session auth, to work out who the user is.
In reality though, most robust JWT systems still require some database calls. For example, we might implement a blacklist for tokens, and often that blacklist will be stored in a database. And even though we get the user ID from the token, we might still want to get extra information about that user, such as whether their account has been deactivated.
Once you have a token, you can access an API from anywhere. This is great for mobile apps, and single page applications.
Tokens are slightly easier to use for mobile phone apps, embedded systems, and micro services.
Most networking libraries do support cookies though, even those on native apps. At the end of the day, cookies are still just HTTP headers.
Tokens are larger than session IDs, so they consume more network bandwidth.
There are many ways this can happen:
So should we use token auth in web apps? We can still store it in a cookie, but that means a web app running on
app.foo.com can't access
api.foo.com. To get around this limitation, you can setup a proxy api running on
app.foo.com, which forwards requests to
Even though you can store lots of data in a JWT, it doesn't mean you should. If you include 'permissions' in your token, those permissions won't expire until the token does. Also, without some kind of blacklist, you can't revoke someone's token until it expires.
Session auth is the stalwart of web authentication. When a user logs in, the web server sets a HTTP-Only cookie containing a session ID. Whenever a request is made to the domain which set the cookie, the cookie is sent in the header.
The web server stores a reference (usually in a database) for the session id, mapping it to the user it belongs to, an expiry date, and any other arbitrary information you want to store for the duration of the session. Each time a request is made, the session expiry is usually updated in the database, so the user only has to login again after say 20 minutes of inactivity, rather than just 20 minutes from when they last logged on.
Sessions are well understood. Most of the large web frameworks use them (e.g. Django).
This is the big problem with session auth. Since the cookies are sent with every web request to the matching domain, a malicious third party website can make requests on a user's behalf. However, it's a well understood problem and all major web frameworks have some kind of CSRF mitigation in place.
The same domain constraint can be challenging. Can proxy via the backend server though.
So which should you use? Tokens are generally preferable on mobile and embedded systems, because they're so easy to work with - call a JSON endpoint, and get a token, then just add that to the header of all future API calls.
With cookies, you have to login, extract the session cookie from the header, configure a cookie jar, and add the cookie to it. It's still not too bad - but some libraries make this harder than others, whilst adding tokens to headers is universally pretty simple. Most endpoints which are protected by session cookies are also protected by CSRF tokens, which also need to be taken into account.
For web applications, session auth makes a lot more sense, mostly for security reasons. Storing tokens in local storage is risky, and if you put the token inside a cookie, you may as well just use session auth. Browser vendors might work out some way of securely storing tokens in the future, but I don't know what this would look like - especially as cookies effectively solve this problem already.
Posted on: 10 Aug 2019
Have any comments or feedback on this post? Chat with us on GitHub.