top | item 11929267

JSON Web Tokens vs. Sessions

321 points| darth_mastah | 9 years ago |float-middle.com | reply

170 comments

order
[+] StevePerkins|9 years ago|reply
For people using JWT as a substitute for stateful sessions, how do you handle renewal (or revocation)?

With a traditional session, the token is set to expire after some period of inactivity (e.g. one hour). Subsequent requests push out the expiration... so that it's always one hour from the last activity, rather than one hour from initial authentication.

With JWT, the expiration time is baked into the token and seems effectively immutable. To extend the session, you have to either:

1. Re-authenticate from the browser every hour and store a new JWT token, which is kind of an awful user experience, or

2. Renew the JWT token from the server side every hour. At least in Google's implementation, this requires the user to grant "offline access" (another awful user experience)... and you'd need some hacky approach for replacing the JWT token in the user's browser.

So with all the recent discussion about not using JWT for sessions, what do you guys do? Do you simply make users re-authenticate every hour? Is there another magic trick that no one has brought up?

In my own shop, we're using the browser's JWT token as a server-side cache key... and storing the "real" expiration in cache so that it can be extended (or revoked) as needed. I would be interested to know if others take a similar approach, or have issues with that?

[+] moyok|9 years ago|reply
For this, you can use refresh tokens and set the JWT expiration to a low interval - say 10 minutes. After every 10 minutes, the JWT expires,authentication fails, and the client uses the refresh token to get a new JWT. To revoke a client, revoke their refresh token. This way, though they won't be logged out immediately, they would be logged out in a max of 10 minutes when they need to refresh again, and find out that their refresh token is no longer valid. The point is that instead of every request touching your DB or cache, only one request does in every 10 minutes.
[+] bigonlogn|9 years ago|reply
JWT is just a token. It's not some panacea of client-side only authentication. There are a lot of people lamenting the difficulty in performing logout via JWT. I believe people are missing the point. The failing isn't with JWT, it's with the implementation of the session system.

Typically with sessions the client has a session key. The key gets sent to the server where it looks up the session (via. memory, cache, database, whatever). You can create a new session, validate an existing session, or end a session. All using that key. They only difference between JWT and cookies is JWTs aren't automatically sent with every request. You have to explicitly send them. I believe this is a good thing. It avoids some common attack vectors.

[+] jcoffland|9 years ago|reply
"1. Re-authenticate from the browser every hour and store a new JWT token, which is kind of an awful user experience"

The old token can be used to request a new token with an extended expiration, before it timesout. This can easily happen behind the scenes, so it does not affect the user experience at all. The real problem is that you cannot enforce logouts.

If you just accept that you cannot 100% enforce logouts and then it works fine. A logout is performed by the client side code deleting the token. There is no way of knowing that all copies of the token were really deleted. It is imperative that HTTPS is used so that the token cannot be easily stolen.

You could also bind the token to a specific IP but this would fail for devices with dynamic IPs that could change at any time.

[+] darksaints|9 years ago|reply
With JWT, you have the option of stateful or stateless. Stateless gives you cheap federation (any server can authenticate a token issued by another server), but you lose the ability to handle revocation without some sort of statefulness introduced (a redis cache with revoked token ids for example). Stateful is basically a non-cookie based session.

One possible alternative to enable auto-renewal is to issue a new token with every request, and manually bake in the persistence of the token into your front end client.

In my own system, I have login with facebook, which submits current FB auth tokens with every request, after which I issue my own app token with all the necessary authorization information for my business logic. Whenever the app token expires, I attempt re-authentication using facebook login, and if successful I send back an updated app token. The front end client has logic built in to compare and swap app tokens if they change and persist in sessionStorage.

It's pretty hacky. I'm a little worried about vulnerabilities that I might be introducing. I luck out in that I don't have a public API which would force the client to implement my front end logic. But it works, for now.

[+] Alex3917|9 years ago|reply
> storing the "real" expiration in cache so that it can be extended (or revoked) as needed.

You can also have a password_last_changed field on your user model, where any token issued before this date is considered invalid. That was if a user's account somehow gets compromised, all they need to do is change their password and then all of their existing sessions are expired automatically.

I can't think of any good reason for storing the expiration dates of each individual token, although maybe there is a use case somewhere.

[+] paulftw|9 years ago|reply
Think how you would do that with session cookies - you either issue a fresh cookie or ask for login/password. Same with JWT - your client-server API wrapper can add a renewed token to a response when needed. There are many other reasons to have central API wrapper on the client (common error checking, serialisation, headers etc) so it doesn't cost much to stick an extra check for a new token
[+] grosbisou|9 years ago|reply
In my system the authentication strategy is the responsabilities of the clients. The auth system only provides tokens via the /auth and /refresh_token routes given respectively a usn/pwd or a valid token.

So the client can refresh the token when they are close to expire or just auth again after expiration.

[+] nawitus|9 years ago|reply
> For people using JWT as a substitute for stateful sessions, how do you handle renewal (or revocation)?

You can do the inverse, e.g. instead of storing 'active sessions', you just store 'revoked sessions'.

[+] Bombthecat|9 years ago|reply
As someone working with it, we use it only for machine to machine communication.

There it is easy to reauth. I don't think jwt was ever ment to used in browsers..

[+] blazespin|9 years ago|reply
you can do a combination of session and jwt. your firewall manages the session, and the jwt can be used internally and effective decouples your architecture and the firewall (except you will need to send a logout message to the firewall if the user choses to logout)

the jwt is useful as a capability model if you've broken your internal arch into stateless microservices.

[+] DenisM|9 years ago|reply
IIRC tptacek has been beating this drum for a while, but it seems that he got tired of it, so I should pick the drum sticks in his stead:

Use less crypto. The less crypto is being used, the fewer mistakes are being made.

When it comes to sessions, generated a secure random 256 bit token and use that as a session id. Store it in a database or in-memory store. Sticky sessions + local session token storage will fix your network latency problems when you start scaling out.

Federation becomes moderately difficult. Perhaps you could store a copy of session id on each node, and when a session id is compromised, proactively reach to all nodes and ask them to purge the session. This allows immediate mitigation for a session id leak, and since it doesn't rely on timeouts there is no vulnerability window for data exfiltratiin upon a breach. And no crypto.

[+] atombender|9 years ago|reply
This misses one huge benefit of JWTs: Other parties can trust your token if they were not the ones to sign it.

For example, say client A calls service B, using a token signed by service C. Previously, we were using randomly generated session keys, which meant B had to ask C every time. But with JWTs, B can directly verify that the token is genuine without asking C, because it has C's public key.

We still check with C now and then, but that's because the token auto-expires. We use a long-lived master token stored in a cookie to generate new short-lived ones.

[+] blazespin|9 years ago|reply
You think mistakes can't be made with session ids? Anyways, there are well trusted libraries out there for JWT.
[+] nbarbettini|9 years ago|reply
> The less crypto is being used, the fewer mistakes are being made.

I don't understand this position. What do you mean by "fewer mistakes are being made"?

[+] nstart|9 years ago|reply
That last part where he talks about logging out being the responsibility of the client is rather key. Basically I can't invalidate the key from the server side. So if a user's account is compromised and they recover it on their mobile app for example, I can't sign the user out of everywhere else too. It's what has given me pause about jwt so far and has held me back from using it. I find the cookie is generally good enough to hold most other information I need about the user.
[+] tjbiddle|9 years ago|reply
I store a `login_count` in my User model. When searching for a user I `find_by_user_and_login_count`. The token they have has their current login_count in the claims. If I want to logout server side, I just update this value (Can be a random string if you'd rather it not be in increasing integer) and it will invalidate all tokens. When they logout client side, of course we can just clear the token from their memory. If they want to invalidate all tokens, then we have an API endpoint for that and it will logout from all devices.
[+] bigonlogn|9 years ago|reply
You can implement sign out everywhere by setting a reauth flag on the user in the database. You lose the "completely stateless" aspect that JWT claims to provide, but it's a small trade-off for tighter security.
[+] btdiehr|9 years ago|reply
Why do you think you can't invalidate a JWT? Store a JWT that is associated with some object in a database that has the field `isInvalidated`. This isn't rocket science. Sure - this turns the JWT token into a session but there is no way to invalidate based on something that isn't determined at creation time without storing something in a database.
[+] aleem|9 years ago|reply
The impact can be mitigated by having low TTLs and using refresh tokens. This will give you a rolling window. If the TTL is 10 minutes and the client doesn't make any requests in 10 minutes, they will be timed out. But if the client continues to have at least one request every 10 minutes the session persist. Session persistence can also be ensured by having your web-client for example make a request to the server every couple of minutes.

Server-side key invalidation is entirely possible but it would require having a blacklist of disabled keys and comparing every requests against the black list. This would obviously concede the benefits of scale from JWT tokens since you are doing the same thing as server side sessions. However, the black list should be considered only as an escape hatch and need not be enabled at all times. In fact, once all the tokens in the black list expire, the black list itself can be disabled and things go back to the way they were.

[+] jcoffland|9 years ago|reply
This is exactly right. Many people confuse this problem with solutions that involve storing state on the server. Doing so completely misses the whole point of RESTful authentication.
[+] tootie|9 years ago|reply
If you need to validate the Authorization header on every request that's not really different than using session tokens we've been using for the past 15 years. JWT is just a formalized way of managing cookies. Which is nice and I like it, but it doesn't actually enable anything that couldn't be done before albeit with a more ad hoc approach.
[+] aleem|9 years ago|reply
Right, Signed Cookies.

JWT doesn't make the claim that it's a new concept, you are assuming as much. It's a standard and as you correctly gleaned and like most other standards, comes with a lot of benefits, best practices, is battle tested and ready-to-use in your favorite frameworks.

It becomes even more useful if you application serves multiple clients such as browsers, iOS applications and so forth because you can hit the ground running without having to reinvent anything.

[+] saynsedit|9 years ago|reply

    [headerB64, payloadB64, signatureB64] = jwt.split('.');

    if (atob(signatureB64) === signatureCreatingFunction(headerB64 + '.' + payloadB64) {  
        // good
    } else
        // no good
    }
You really need a constant time compare for the signature, else you leak information about the correct signature in the timing of the response.
[+] jsmeaton|9 years ago|reply
I don't think this is true. Timing attacks are only really useful if you can change a single piece of data and analyze the time difference until you find the right value, over and over again. Like comparing a password.

The unknown data in the signature creating function is a key. The output is a hash. If you were trying to capture the key you would need to guess what the key was to get the correct hash. Each byte you change results in a cascade of changes in the output. You can't get information about the key from a timing attack on a hash function. I think.

[+] hit8run|9 years ago|reply
A similar approach are encrypted cookies. You can take data and sign it. The server can then check if the cookie data is correctly signed and accepts or rejects the data in the cookie. This approach also scales horizontally. I use it for a while now in go (http://www.gorillatoolkit.org/pkg/sessions). If you want you can also encrypt the expiry date into the secured cookie.
[+] Xeoncross|9 years ago|reply
Yes, I've been using encrypted cookies for years. If the user wants to use my website - they can store their own session data.

The trade-off is extra bytes over the wire as the cookie is sent each same-domain request.

[+] zatkin|9 years ago|reply
Aren't cookies the safest approach for storing authorization tokens? I recently found out that both Google and Facebook use cookies for authorization, so it seems like the way to go, though I've read that it gives programmer headaches.
[+] scope|9 years ago|reply
Cookies can be/are used for extensive tracking (even when you're not techically on the site). The EU requires websites that use cookies to display conformation message on how cookies will be used to track the user.
[+] jcoffland|9 years ago|reply
This is a practical implementation of something I described on stackoverflow in 2013. http://stackoverflow.com/questions/319530/restful-authentica...

The discussion there is rather interesting. The problem of invalidating logins is discussed. I have not found any satisfactory solution to this problem. You can set a timeout on tokens but then the user would have to log back in periodically. If the software can renew the token automatically then there is nothing to stop an attacker with a stolen token from doing the same, indefinitely. Still, in many situations these problems are no worse than compromised session based logins.

[+] niftich|9 years ago|reply
Serious question: are there any opinionated frameworks that use JWT for session-like or session-replacing ways?

There was one was linked in this thread [1], but how did framework authors tackle this domain? Is everything discussed here entirely homegrown, ad-hoc? Is this something that every one of us has to read up on and re-implement every time?

[1] https://github.com/hharnisc/auth-service

[+] carapace|9 years ago|reply
Reminds me of "macaroons".

http://research.google.com/pubs/pub41892.html "Macaroons: Cookies with Contextual Caveats for Decentralized Authorization in the Cloud"

[+] arnarbi|9 years ago|reply
It's unfortunate that the JWT encoding scheme of the signed data (non-normative JSON -> base64 -> concatenate with a dot) does not lend itself well to hash-chaining. JWTs could have been a great standard encoding for macaroons.

(disclaimer: I'm an author of that paper)

[+] skybrian|9 years ago|reply
I didn't understand this part:

"if your application maintained a list of key/algorithm pairs, and each of the pairs had a name (id), you could add that key id to the header and then during verification of the JWT you would have more confidence in picking the algorithm"

This implies there's a security benefit, but I don't understand how it's better than checking the alg parameter against a whitelist. Perhaps if you're using non-standard names for algorithms, that guards against mistakes?

[+] Bino|9 years ago|reply
Why the obsession with 3 letter short names? Why "typ" and not "type". I'm sore the overhead can be ignored and the parser doesn't care.
[+] jcadam|9 years ago|reply
So, I've started working on a new project recently, and thought I'd use JWT (instead of Ye Olde cookie-based sessions). After working with it for a bit, I've decided that I can probably get away with using it for authentication, but definitely NOT for authorization.

I'm using a kind of RBAC and storing Roles in the JWT just seems like a bad idea. Header size is one issue, but also there is the problem of granting/revoking a role and having that change reflected immediately (rather than waiting on the token refresh window).

So, now my API requests happen thusly: "Ok, I have a valid token for User X, so I accept that this request came from User X. Now, let's check User X's roles in the database to see if they have permission to perform action Y on resource Z..."

Hmm... I'm not sure this feels right.

[+] moyok|9 years ago|reply
The thing that scares me about using JWT is that all security completely relies on the one secret that is used to sign tokens - any person with access to that secret has got potentially unlimited access to the app. They can now impersonate any user and do basically anything.
[+] wtbob|9 years ago|reply
Yes, it'd be better if JWTs were full-fledged certificates, where ultimate authority could be confined to some offline key, who delegates authority for strictly delimited period to online keys. Or ultimate authority could belong to k out of a collection of n keys: one would need to suborn k keys to suborn the authority as a whole.

RFCs 2692 & 2693 specify a really great, lightweight, way to do that. They resulting certificates needn't be a whole lot heavier than a JWT, and are much lighter-weight than and X.509 certificate. The RFCs also specify an intelligent, domain-neutral algorithm for performing calculations on tags (what JWT refers to as 'claims') and keys.

It's a pretty awesome solution, and there are a lot of good ideas in there. A streamlined version could, I think, end up being competitive with JWTs.

[+] stephenr|9 years ago|reply
I've had this "them: we should use JWT, it's easier to scale; me: the customer has 200 clients, they don't need to scale shit, sessions are fine" argument before, and honestly at this point I'm pretty convinced JWT isn't a replacement for session auth.

The one place I can see it might be useful, is when you need to give a third-party system some kind of access to your API, as an alternative to storing a secondary hashed field(s) for api keys.

[+] spriggan3|9 years ago|reply
A few years later : "JWT in place of sessions considered harmful".
[+] hharnisch|9 years ago|reply
JWT is especially useful for validating requests in a microservice architecture. You can pass around the token an embed roles in them. No need to keep a session store with them!