Hacker Newsnew | past | comments | ask | show | jobs | submitlogin
Don't use JSON web tokens for sessions (cryto.net)
226 points by joepie91_ on June 13, 2016 | hide | past | favorite | 147 comments


    You cannot invalidate JWT tokens
This is simple not true. You ALWAYS will sign your tokens with a well known secret, you could eventually even add some salt from a database to it.

    They are less secure
Compared to what? Actually JWT will have the same secureness like Bearer Tokens or Cookies, wherever you store it, its not `less` secure. Horrible article points here.

    They are less secure
They take the same amount of storage than signed cookies, wuhu I use JWT so often and I NEVER exceeded the cookie limit, but I wouldn't store them there anyway.

JWT is as secure as any other solution and this article proves it since he isn't well informed, he just throws a bunch of stuff out and tries to be "an expert". Btw. every other solution is really dangerous as well, especially Cookies could be a total mess of security problems. The same could actually happen with Bearer Tokens.

My toughts are use the thing your most happy with and the thing you understand and the thing you can implement with code that is totally clear and especially code that is really really easy to understand. And actually JWT will mostly win this battle.

I've seen a lot of people just using Session Cookies from their Framework, but eventually have no idea about their risks, they have lots of CSRF all over the place, or using a too small ID or eventually the ID is not really random. Eventually this could happen with JWT too, tough. As seen by this guy, that he generates the JWT without any well known secure string. that could be changed.


    You cannot invalidate JWT tokens
        

    This is simple not true. You ALWAYS will sign your tokens with a well known secret, you could eventually even add some salt from a database to it.
I think one of the benefits of some (most?) JWT implementations is that it doesn't hit the database on every request - the token is only validated against a global secret.

So you can't invalidate a single user's session without invalidating all users' sessions.


I keep a counter in the JWT to at least mostly get around this issue. When processing a request, the counter is checked for the user, which isn't a big deal since all of the requests already require looking up the user. A counter increment invalidates all of that user's existing tokens.

If a user changes their password, their roles change, etc, then the counter gets incremented so all tokens issued up to that point won't be valid anymore.


Can you explain this a little bit more? You keep a counter on the user object in the DB? What is the JWT buying you if you still have to hit the DB on every request?


Presumably you can keep counters like these on the server edges, and just push new values out to servers whenever things change, as opposed to query a DB every time. This wouldn't invalidate individual tokens however, but all tokens that have that counter value. It'd also mean there's a window where tokens can still be used while servers are being updated with the new value(s).

These are just some random and half-baked thoughts, I have no idea what OP does, but there are options to limit hitting backing DBs anyway.


Yep ^ This is what I often do too. Simple, but effective.


That's pretty smart. Effectively versioning your issued tokens. Way easier than maintaining a blacklist.


You can store the user info in the JWT so you don't need to hit the database to get user info every time. I usually just store an id in each issued token and store/remove it from redis or memory as needed for invalidating it.


You have to be careful that you are not leaking sensitive info though, as the JWT payload is meant to be visible on the client as well.


Yes you can. The system I built uses a revocation list (propagated to all servers in the cluster) to invalidate the session.

Just as if you were storing state on the server, it still requires a means of propagating the user's state to every server. But we only need to propagate a single ID once per session (at logout) instead of propagating all the session data to all the servers on every request.


To revoke with a revocation list, you need to know the ID of the token being revoked. That only works if (a) the token is present at the event that triggered the revocation, or (b) you are tracking all tokens, in which case there's probably not much point to using JWTs at all.

Another approach is what I call the "subject epoch" pattern. The subject of a token (the "sub" JWT claim) is often something like a user ID. When an event occurs that requires all tokens for a given subject to be revoked, save that time stamp as the subject's "epoch". When processing JWTs, those issued before the subject's epoch must be considered invalid.


Do you ever worry that, in the case of failure or some other event, your revocation list could be lost and allow old hacked sessions to be used?

Is there a way around this? I like the idea of a revocation list, but this seems to be a pretty big concern.


Not particularly. There are other layers of security here - the sessions expire (so there's a limited window to exploit each one), the sessions are always transmitted via SSL (so you pretty much have to have an exploit on the customer's system to get one), and the sessions are restricted to one customer (so you only have an attack against the customer whose system you have an exploit on).

If we used a different approach, then the same error (losing the data that's being synched) would result in losing all of the customer sessions.


The same problem occurs on every other method. i.e. Bearer/Cookies. As already said the most vulnerabilities applies to all methods. But people are just too blind to see that.


"old hacked sessions to be used"

JWTs generally contain an expiration timestamp.


revocation list only needs to contain tokens that haven't expired. If there is an 'event' that causes this info to be lost, then expire everything by changing the global secret.


Out of curiosity, how are you propagating the IDs to other systems in the cluster? I am building something which could benefit from pushing config data across a cluster.


In most cases it shouldn't matter; revocation lists ought to be trimmed to the lifetime of the issued tokens--when they are used at all, revoking a JWT rather than just letting it expire is likely not extremely common--so you could stuff them anywhere at all that is convenient to your other technology selections.


it's my understanding something like Redis is good for cross cluster im-memory persistence/reference


I hit the database on requests - I keep their identity in the JWT but not their permissions. And if they're hitting a protected route (the only time their identity is necessary anyways) you best be sure I'm checking their canonical permissions.


You might be, but many people use signed cookie sessions in order to avoid having to check the DB.


Can't you maintain session state in a Redis daemon and invalidate it there? Or are you talking about stateless JWT?


You include the time created in the object before signing, and invalidate based on that as a timeout.


Sure, but that's expiration, not invalidation, ie. we're talking about the ability to declare "this particular token is invalid now".

Incidentally, this limitation isn't too surprising to me... Is there any possible token-based authentication scheme that is both stateless (ie. no round trip to the database on every call) AND invalidate-able? Seems like any form of invalidation would require storing the "is valid" state somewhere else...


> Is there any possible token-based authentication scheme that is both stateless (ie. no round trip to the database on every call) AND invalidate-able?

I suspect this is provably impossible.

There are all sorts of things you can do at the protocol/platform level if you have a shared secret, but with only the constraints of an open authentication scheme you lack the tools to do this.


If you're willing to delve into the fun world of CRLs you can sorta do it. This isn't truly stateless of course, but for some design constraints it could be "practically" stateless since you're eliminating auth server round trips, which is probably why you were aiming for statelessness in the first place.

CRLs of course introduce lots of replication complexity and timing bounds to consider, and you probably want to pair them with short lived tokens to keep the CRL size manageable. (and then delve into refresh tokens)

As the OP points at, you most likely don't need any of this.


Eventually JWT has very little Roundtrips.

Our current Implementation is:

- Really short lived JWT of 1 minute - If the JWT is invalid and the user didn't do a request in the last minute it does query the database for a session token (we use session tokens and jwt). if the Token is inside the database/redis/ehcache/whatever the user gets still a new JWT token.

Actually we did that since we needed a "sane" way of revoking tokens fast but still keep the user logged in until the browser is closed.

We don't have a mobile client (yet) but I guess we try to do something like that, too. just not with a session. This works really well and mostly our users won't hang around for more than a minute and when they do its not a problem to have a single backend call.


> stateless (ie. no round trip to the database on every call)

AFAIK, Stateless is about independent request/response and not needing a server to retain session information through the course of multiple requests. It has nothing to do with whether or not you're checking a database to cross-reference credentials - and I wouldn't keep anything more than an ID/name in a JWT... ever.

https://en.wikipedia.org/wiki/Stateless_protocol


JWT is good for much more than an ID+name; it's sensible to allow your partially-trusted token issuers to vouch for a _limited_ set of user roles and the like. Just the same way you probably wouldn't allow the @acme.com security authority to vouch for @example.com principals in a multi-tenant system... in ye olde SAML lingo this is called "claim filtering / transform / passthrough."

Practically speaking, we use a bit of metadata (jsonb documents in pgsql, mostly) for each JWT-issuing party, which describes how to validate principals, how to map incoming claims to "our" claims (e.g., "by what name does sts.acme.com call a 'role'? is sts.acme.com allowed to vouch for the 'admin' role?) in addition to the more central things like shared secrets, certificates, etc. This kind of partial trust is how claims auth is supposed to work, and avoids any unnecessary provisioning/syncing of user details.


> Is there any possible token-based authentication scheme that is both stateless (ie. no round trip to the database on every call) AND invalidate-able?

SPKI (RFC 2692/2693) solved this in 1999, with its timed CRLs. Exactly one CRL is valid for any given period of time: when a token (= certificate) is received, it is invalid if it is referenced in the CRL, and valid otherwise.


Your first point is mostly dead on. I see a number of people stating that you cannot revoke a token, and it's simply not true.

The approach I use is to replace the shared session store (which is large, grows linearly with your user base, and hard to sync across clusters if you need that) with a shared revocation list.

The revocation list is small, easy to check, only contains IDs and a TTL, much less cumbersome to replicate... And is functionally equivalent.

If you have already gone the route of using a token for your session, it's really easy to implement and scales much better than a massive in memory store.


The point of using a stateless token is that you don't have to hit a central server / service to verify each token. If you need to do that in order to check for revoked tokens (for each request) then that defeats the purpose. At that point you may as well just check the original token / key for validity.

The difference in speed between checking for a token in the big pool (all tokens) vs the small pool (revoked tokens) should be a lot smaller than the round trip to token server (i.e. network cost).

Also, you should be able to easily store millions of tokens on a single server (something like Redis). Do you really have a site that has multiple millions of people logged in?


Sorry if that wasn't clear, but I absolutely agree you should use a distributed revocation list. As each request comes in, you need to check the list. But you do need to check the list, and you do need to distribute it widely.

Depending on your situation, managing a revocation list in memory at each edge node might be feasible, reducing the overhead of a network call to a per-cluster store, which is another advantage of using a short revocation list instead of a large session store that can't feasibly be shared like that.

(Edit: looking back at my comment, I shouldn't have said a "shared" revocation list, but a distributed one. Whoops!)


actually I often see stating that you should rely on a 3rd party authentication library since its mostly well known and well tested. While I would agree here I know that mostly the library will be your weak point since you have no idea how its implemented or whenever a new version comes around if it maybe has a security issue or if you keep your version if your vulnerable to something.

Actually most people should take their authentication mechanism as something really really important and not just rely on something. It's really important that your authentication/authorization stuff works and is hardened, not just for you, also for your users. I know that auth could be really hard, especially when the language of your choice contains some bugs, but its a nogo to just use something when it is that important. I don't mean that you can't use a library, but if you do please double check the code twice on each version.


I actually think your advice is more harmful than helpful - web developers are not renowned for writing secure software. This is a very good case of finding a good, well-tested and vetted library that does this. Not sure what options exist, but I would be highly surprised if there weren't any already.


There are two common mechanisms for invalidating tokens:

* Store the invalidated tokens in some fast store, in memory store and check that before accepting tokens.

* Have auth tokens be very short lived (e.g., 1 minute) and require the use of a "refresh token" to get a new auth token when it's expired. This is the mechanism used by OAuth 2 (which strangely is never mentioned in the article). The refresh tokens should be random strings stored in a db, and they can be simply deleted on invalidation.


The second one is recommended by the article. They are differentiating between session and auth tokens, however.


   You ALWAYS will sign your tokens with a well known secret, you could eventually even add some salt from a database to it.
Exactly. Each JWT I generate has a salt inside which I store in the DB, and ideally the salt has accompanying data such as the datetime the JWT was generated, the IP address that generated it, etc. Now you can provide an interface that lists "sessions" and allows the invalidation of logged in sessions by deleting the salt from the DB, rendering the JWT invalid.


Using IP addresses for session (in)validation is pretty useless now that everybody has a mobile device that moves between networks (WiFi at home, WiFi at work, 3G/4G). If you use the website while walking from WiFi to 4G you would lose session.


This is for the use case of: "Something weird happened on my account, so I check sessions and see that someone used my account from across the country. So I log out other sessions."


I asked this question below, but how do you use the payload to select the correct salt from the database in order to verify the signature before verifying the signature and confirming that the payload is valid?


one way would be:

    - generate the salt
    - generate the jwt
    - use the header base64 string as the key for your database
    - store the salt with the header base64 as the key in your database
maybe?

just one idea, basically when you are > 100.000 users you barely invalidate a single token. mostly you would kill of your secret which will invalidate any token anyway. but there are numerous ways of doing so.

Edit:

to the poster after me:

actually we never needed to logout a single user. but actually our authorization is not stored in our JWT so if we want to kill a user off, we could just remove any rights from him so he gets a site where he needs to either logout or refresh (which will show him the same site again).


Invalidating the site secret is my go-to strategy right now, but I have wondered how to sign out a single user across all their logged-in devices. Anyway, this idea is interesting and would be pretty straightforward to implement. Thanks!


The point is to avoid all the database updates. So, I would recommend not going that route.

If you need to sign out a user across all logged-in sessions, use a revocation list based on UID, rather than token-id.


yep probably the better idea. eventually we combine sessions and JWT Tokens. The session id is kind of a refresh token that refreshes the token if it was expired and the user didn't generate a new token in less than one minute. than it will use the session id will query the database and create a new token if the session is still valid.


Maybe you could salt the secret per user and store it in the DB. This would allow users to have a feature like "Logout from all devices". I am not sure how you would query the database to get the salt? JWT as key and salt as value? Or maybe sending userId with each request?

Anyone know any good articles I can read on the topic?


The extra salt is probably unnecessary if you require (and validate) not-before and not-after dates on each token. I couldn't say more without knowing the details of your implementation, but "secret salt" strategies often are a band-aid over some more fundamental problem.

Whether it is good to bind the JWT to some combination of user-agent, device cookie, IP address (not recommended) or whatever, is a separate topic...


Wait. You have individual salt for each user that you store in your DB?


More than that. A salt for each "session".

Each JWT contains two pieces of info: user ID, and salt. This stops the JWT from being a deterministic token that is always the same each time a token is generated for a specific user.

It also allows invalidation. On each request a middleware checks validity of the salt from the JWT. A Redis cache layer here makes this a 1-2ms operation and easy to scale. If you need to invalidate a JWT delete a salt and the respective token is now invalid. Or delete all salts for a user to invalidate all their sessions.

Honestly this use of a JWT is basically just a lightweight session that passes the session ID via a technique that isn't insecure by default like cookies are. Rather than having to opt in to CSRF protection your stuff is hard to CSRF unless your application persists the token insecurely.


Salt is random data used to cryptographically sign or encrypt data. It sounds like your JWT consists of a userID and a sessionID (stored in Redis).

Why not just store your sessionID in a cryptographically signed HttpOnly cookie? In most use cases, it'd be less ambiguous, better protected from JS attacks, and equal-or-less vulnerable to CSRF.

https://en.wikipedia.org/wiki/Salt_(cryptography)


> This is simple not true. You ALWAYS will sign your tokens with a well known secret, you could eventually even add some salt from a database to it.

This refers to invalidating individual tokens. I've just updated the title and text in the post to clarify that.

> Compared to what? Actually JWT will have the same secureness like Bearer Tokens or Cookies, wherever you store it, its not `less` secure. Horrible article points here.

Compared to storing something in a cookie. The article explicitly states that this concerns JWT tokens that are not stored in a cookie. And comparing "JWT vs. Cookies" makes absolutely no sense, they're different kinds of things.

> They take the same amount of storage than signed cookies, wuhu I use JWT so often and I NEVER exceeded the cookie limit, but I wouldn't store them there anyway.

Again - the article explicitly states that this refers to stateless tokens, ie. where the data is contained in the token itself. Did you actually read the full article, or just the headers?

> JWT is as secure as any other solution and this article proves it since he isn't well informed, he just throws a bunch of stuff out and tries to be "an expert". Btw. every other solution is really dangerous as well, especially Cookies could be a total mess of security problems. The same could actually happen with Bearer Tokens.

Personal attack and hand-wavy statements without ever actually addressing any specific security concerns. Take that elsewhere. I'm here for technical discussion, not for throwing shit.

> My toughts are use the thing your most happy with and the thing you understand

No, that is not how security works.

> and the thing you can implement with code that is totally clear and especially code that is really really easy to understand. And actually JWT will mostly win this battle.

No, it won't. The typical framework will only require you to load a single plugin to get sessions working, and literally nothing else. JWT tokens require manual handling.

> I've seen a lot of people just using Session Cookies from their Framework, but eventually have no idea about their risks, they have lots of CSRF all over the place

That is a separate problem, and you don't solve that by storing your session IDs differently and trying to sidestep it. You store it by actually mitigating the problem you are having, which means adding CSRF tokens.

That's the only actually secure solution to this problem - "manually handling sessions" and "secure session storage" are mutually exclusive, and automatically handling sessions will always be vulnerable to CSRF problems.

> or using a too small ID or eventually the ID is not really random.

Use a well-tested implementation - as, again, I have stated in my article - and this will not be a problem. Don't roll your own session implementation.


I disagree with his argument that JSON web tokens are "less secure". He even quotes this:

> The only way to retrieve data out of local storage is by using JavaScript, which means any attacker supplied JavaScript that passes the Content Security Policy can access and exfiltrate it.

In my opinion, it is MUCH easier to get a CSRF vulnerability than it is to bypass the Content Security Policy. Unless you can get around the CSP and same origin requirement, this makes web tokens far more secure.

He also states that if you store your web token in a cookie you are still vulnerable to CSRF. This is only true if you are using cookie headers to send the token (which is less common), not if you only use it for storage/retrieval of the token.

Lastly, he argues JSON web tokens are not easier to use, but then points out you need a dedicated Redis session store server to scale session authentications. Managing sessions in mobile apps and command line apps is a huge pain compared to JWTs. How is that easier to use?


The crucial point is that XSS vulnerabilities are an application level issue. If you have an XSS vulnerability, your application is broken. Good development practices prevent XSS vulnerabilities.

Your application does not have a CSRF vulnerability; HTTP cookies have a CSRF vulnerability. Your application may depend on HTTP cookies, which exposes this vulnerability through your application. The so-called "CSRF protection" is a hack that patches a protocol vulnerability at the application level.


I've tested many web applications, and around 80% of all applications I've tested contained an XSS of some sort or another, that number drops to around 40% if you only look at stored XSS & XSS in a get request. And to less than 10% when only looking at stored XSS.

Unless you've used cookies with the HttpOnly flag XSS trivially escalates to session stealing. Do NOT store sessions in anything other than cookies with the HttpOnly (and really, SecureFlag) flag set.

Using javascript to manage your sessions only the client side in any way is NOT secure.


> Unless you've used cookies with the HttpOnly flag XSS trivially escalates to session stealing

Then again you could just use CSP and mitigate almost 100% of those XSS cases. Yes, even most of the stored ones. And with JWT + JavaScript you don't have to worry about all the oddities in the way cookies work, which is a huge plus.


CSP isn't a silver bullet.


Nor is HttpOnly, really.


I never said it was.


if you are vulnerable to XSS your HttpOnly cookie won't help you.


You are wrong. It does. It keeps your user's session from being trivially stolen. In practise this makes successfully executing attacks harder. It's not a _nice_ thing to have, it's essential.

An example of this is an application that asks you to confirm <action> after a POST or w/e. If your XSS vector is not in the new page, then you can't execute <action> as an attacker automatically.

Many, many, applications (not only on the web) implement such a scheme.

A stolen session is MUCH more valuable to an attacker than only a raw XSS.


It does not. It is the difference between an exploit that yields a root password and one that yields a shell at uid=0.

HttpOnly is almost totally cosmetic.


It's not the same, an XSS is not comparable to a shell for the exact reason I outlined above. And a session is not a password.

I'm probably coming over as too offensive, but you really really don't seem to know what you are even talking about. You are wrong wrong wrong.


If you don't believe `tptacek maybe you will believe James Kettle:

http://blog.portswigger.net/2016/05/web-storage-lesser-evil-...


I'm pretty sure? I do know what I'm talking about here. Sorry. HttpOnly is a joke.


> Using javascript to manage your sessions only the client side in any way is NOT secure.

And yet it's common practice, at least in the SPA communities with which I engage on a regular basis.


CSRF vulnerabilities are less severe than a stolen session. I've addressed the reason for that here: https://www.reddit.com/r/PHP/comments/4nwpvg/stop_using_jwt_...

> This is only true if you are using cookie headers to send the token (which is less common), not if you only use it for storage/retrieval of the token.

That's the normal mode of operation for cookies, and what you should assume the client to do.

> Lastly, he argues JSON web tokens are not easier to use, but then points out you need a dedicated Redis session store server to scale session authentications.

At a scale where you can't just store the sessions in the database you're already using (or on disk - see PHP), the added complexity of a single Redis server is negligible. Below that scale, you can just use your regular database, at no additional complexity cost.

> Managing sessions in mobile apps and command line apps is a huge pain compared to JWTs.

I've heard a few people claim this now, but none have been able to explain exactly how it's a "huge pain" or "more complex". Care to elaborate?


> In my opinion, it is MUCH easier to get a CSRF vulnerability

It's simple (though perhaps non-trivial) to protect against XSRF these days, especially if you're securing a JSON API, with:

1. the SameSite cookie option (Chrome-only for now)

2. double submit cookies (mentioned in the article)

3. filtering by the Accept request header, i.e. blacklist application/x-www-form-urlencoded, multipart/form-data, and text/plain, or whitelist application/json (protects against non-XHR, form-based attacks; only appropriate for JSON APIs)

4. CORS, i.e. disallow cross-origin requests, which is the default when no Access-Control-Allow-Origin response header is present (protects against XHR attacks; only appropriate for JSON APIs)


To your last point, if you want to be able to expire "other" tokens for a user on, for example a password change, then you need to check/verify the token against a datastore on each request anyway... the same will go for access/api throttling. Which will negate some of the enhancements that "stateless" JWT gives you, as it's no longer stateless.

Of course, you can selectively "verify" the token, only doing signature validation for most requests (semi-public, browse, ...), but security-sensitive requests validate the token hasn't been revoked (checkout, profile mgt, etc), or is otherwise still valid.


So, if I'm reading the advice right, then ...

  * Using JWT for authorization, particularly for one-time use == GOOD
  * Using JWT to represent long-lived persistent session state == BAD
and, always transmit your tokens in all directions over HTTPS.

This seems like useful advice given all the reasons put forward. Do I understand correctly or did I miss anything?


That's it in a nutshell. A lot of developers also misuse JWT in strange ways, and the meat of this article was responding to those weird/unsafe use-cases.


Haven't used JWTs myself, but whenever I read an article or tutorial about them, it's always in the context of replacing session cookies.


That's pretty much a perfect summary, yeah.


Yeah, pretty much. JWT is a very good and useful spec, I think particularly in distributed systems, but it's no panacea.


This article is deeply troubling from a factual standpoint and I hope people do more research when considering JWT.

Points; 1) His terms are confusing and just plain wrong. Backwards even. For example, he calls storing an id in the token and session data server-side as stateful. That is incorrect; there is no state stored on the client, it is all server-side. That is by definition a stateless session token. 2) A lot of his claims of why people recommend JWT are unsubstantiated and frankly, I've never heard them before (like JWT is better for mobile... what)? Maybe I would feel better if he provided references but a lot of those points are just plain misinformed (or imo, made up). 3) "You will not need stateless sessions" is like saying O(n) performance is usually good enough. Well ok, until it isn't. Don't assume some worst case performance on your site won't occur. Build defensively, knowing where you might have a bottleneck (DB I/O for instance). It's not just 'future proofing". It's good engineering, damnit. 4) It's hard? Give me a break. 5) It's inflexible? You can store an entire JSON object in a JWT. That is incredible flexibility. 6) It's not that secure (whereas cookies in his opinion are)? This is just blatantly false.

Ok, I'm tired of debunking this article. Plain and simple, this article is not just misinformed but dangerously wrong. I appreciate Sven trying to share his insight with the community of developers but most of what he says is wrong.

I use JWT for stateless session management backed by some clever database optimizations (at least I like to think so). If you want to know more ask, but please, do not use this article to guide your decision on whether to use JWT (or a similar secure token scheme).


Ill chime in with my $0.02

* Inability to invalidate stateless JWT tokens can be more or less be remedied with a short expiration time of the token and a token refresh flow. If a token is only valid for 5 minutes, and you can only refresh the token during that 5 minute window, it greatly reduces the attack vector. If that risk is too high, you should easily implement state with the same Redis setup that author mentions

* a classic CSRF example where youre logged into your app in one tab and you open a malicious link in another tab is not a threat if you, like the author suggests, use cookies for storage, but not for authentication. If you pass a token around in an "Authentication" header and have the server IGNORE the cookie which will inadvertently be sent, the request made in another tab via a malicious website is not going to be authenticated.

There are definite Usability and security pros to using Session cookies for storage:

* Unlike Session Storage, the cookies are visible by your application if you have two instances of it running in different tabs/windows.

* Unlike Local Storage, session cookies get wiped out when the user closes their browser


Yes, I like this approach and it creates the opportunity for a hybrid approach between stateless JWT tokens and stateful sessions:

* JWT tokens can have a "short" expiration time, as you suggest, and within that time can be used in a stateless manner -- i.e. they do not need to be validated against a central session store, etc. * The refresh token process can use a more traditional session type configuration, where the token is checked against a central session store. The refresh can be refused if the central "session" has been revoked, e.g.

This to me gives you all the benefits of JWT (e.g. you can use federated authentication services) and the benefits of a centralized session store (e.g. easy revocability).

The main concern would be if you needed more "immediate" revocability within the stateless time frame. One solution would be to implement a "blacklist" that holds a temporary list of revoked tokens (and a token only needs to live on that list for as long as its expiration window). Alternatively, at that point you could just stick to a traditional session.


If you give the tokens an expiration time of 5 minutes, the application either needs to auto-request a token every 4-5 minutes automatically using a JavaScript timer, or your session times out way too quickly. If you close the tab, you will be logged out within 5 minutes. That may not be desired in many applications.


You don't have to use a timer, you can also do it when you're about to use the token, or after the token has been rejected if you're so inclined. I.e. before you make a request you check the validity of the token and if it's not valid you refresh it; or if you don't do this validation you'd have to deal with the server rejecting your token, doing the refresh, and then trying the original request again.


That correct. You would use the timer to auto-refresh the token.

Note: if you close the tab, if you use a session cookie for token storage, its likely to remain, but like you said will become invalid within 5 minutes.

If you close the browser however, a Session cookie will be deleted, which mitigates an issue in a shared setting.

Depending on the requirements, you can ask a user whether they are using a shared pc or a private pc and choose cookie storage at that point.


This articles doesn't acknowledge where JWTs really shine: Authentication across a cloud of services, esp. a microservice architecture. JWTs allow a session to be shared across all of the services without any shared state.


I intentionally didn't address this in the article (and went for the "download server" example instead), because there's too much risk of people implementing my (simplified) description verbatim, and ending up with a whole host of security issues.

To address your usecase: This is perfectly possible without using JWTs as a session store. Your individual services will be either stateful or stateless.

If they are stateless, you can simply use single-use tokens that are issued by the application server, and the entire concept of "sessions" doesn't exist as far as that service is concerned. The only thing it cares about, is whether any particular one operation is authorized.

If they are stateful, you can simply maintain a separate session for each of the services. You then use a short-lived JWT token (issued by the application server) to authorize the creation of a session on a non-application-server. The client exchanges this for a session on the non-application-server.

This way you essentially get the best of both worlds. Of course that leaves you to still have to implement (relatively complex) revocation infrastructure yourself for the stateful services, but that's inherent to a distributed architecture.


Totally, we started doing that and haven't looked back.

Btw, if anyone is looking for an easy way to get going with Node.js check out https://github.com/davidguttman/authentic


It does actually acknowledge it, at the end of the post: "So... what is JWT good for, then?"


I don't really see what JWT got to do with it. It's just an encoding format, and whether you put session state in the token is orthogonal.


Your architecture being microservices doesn't change the problems with using JWTs (or any "session" system based on signing things): you can't revoke them.

I am pretty confident being unable to revoke tokens will start to be a problem with any sufficiently large websites: you don't just need to scale in terms of traffic, but also in terms of people doing bad things.

If you're at this sort of scale, adding in another service that validates sessions is not a lot of work. Either your microservices that need authentication could have a library added to talk to this service, or you could put everything that needs auth behind something that validates the requests as they come in. Vulcand looks like it makes this easy (I haven't used it personally, but I've worked on a system that works similarly using an F5 device).

Sooner or later, you _will_ regret not being able to revoke sessions.


You can (and should) use a revocation list. This is really no different than doing invalidation/revocation of stored sessions because you have the same job of sending the session/token ID out to all dependencies. But, instead of keeping a giant memory store of all sessions in sync across clusters, you only have to keep a short lived list of revoked tokens. Less noise, less memory, same difference.


Say an account gets hijacked, I want to invalidate all the sessions. How do I do it? I have no list of all the sessions that are currently out there for them.

Also: I am thoroughly unconvinced that keeping a short list of data synced across clusters is in any way easier than keeping a long list of data synced across clusters. It has the same performance requirements and the same distributability requirements. Why is this easier?


> Say an account gets hijacked, I want to invalidate all the sessions. How do I do it? I have no list of all the sessions that are currently out there for them.

The revocation list could include entries of the form (revoke-all-tokens-before USER TIMESTAMP).

You can also use stateless tokens and store them in a database until they each expire, and then just list all outstanding tokens for the user in your revocation list. Nothing says you can't use a stateless token and store it.

> Also: I am thoroughly unconvinced that keeping a short list of data synced across clusters is in any way easier than keeping a long list of data synced across clusters. It has the same performance requirements and the same distributability requirements. Why is this easier?

You have to execute your consensus protocol once for each datum synced across the cluster. It's cheaper to run that protocol once each for a short list of items than it is to run it once each for a long list of items. 'Hey everybody, please invalidate the following item, confirm!' once in a blue moon is cheaper than 'hey everybody, someone logged in, confirm!' over and over again.


What does the revocation list look like? "Reject all tokens for user X issued before timestamp Y?" Or do you assign UUIDs to your tokens?


I assign a unique ID for each token (the `jti` claim). So each token has a unique identifier and can be invalidated that way, and every token has the user's ID (the `sub` claim), and can be invalidated that way, if that fits your use case.


I read this wrong the first time. That makes sense. Thank you.


I think this assumes that people are switching from server-backed sessions to JWT. I'd expect instead that most people (and frameworks now-a-days) use signed cookies instead. Switching to JWT just standardizes that format a bit to allow non-web clients (like mobile apps) to use a similar session.

I think Armin Ronacher's blog post[0] is a good overview on the benefits of using signed client storage for session state.

[0]: http://lucumr.pocoo.org/2013/11/17/my-favorite-database/


JWT is often used as an implementation of signed cookies.

Also, don't use signed cookies unless you have a crypto expert on staff.


> Also, don't use signed cookies unless you have a crypto expert on staff.

As opposed to what ? re-implementing cookies from scratch with JWT ? JWT is a dangerous system because it's even harder to get things right. Cookies and their flaws have been documented for decades, no need to be a crypto expert to sign cookies.


> no need to be a crypto expert to sign cookies

You literally just said the equivalent of "no need to be a crypto expert to implement cryptographic signatures."

Please don't do that without a crypto expert on staff. They'll be able to avoid side channels that non-experts will never even imagine. To wit: http://blog.ircmaxell.com/2014/11/its-all-about-time.html

It's just a bad idea all around.


>You are essentially powerless, and cannot 'kill' a session without building complex (and stateful!) infrastructure to explicitly detect and reject them, defeating the entire point of using stateless JWT tokens to begin with.

just autoincrement nonce=123 and revoke it any time. Nothing complex about it.

>it can also mean somebody has a token with a role of admin, even though you've just revoked their admin role.

nobody stores user mode in session, that's what DB for.

>but without the battle-tested implementations.

"I don't know what's wrong but I'm kinda afraid to try".

Best argument so far is that it's indeed longer.

Bottom line: Use JWT for sessions, they are awesome! In Rails we're using similar mechanism for years already.


> just autoincrement nonce=123 and revoke it any time.

Does that revoke all tokens (shared "nonce") or update the token on next authentication? Would this "nonce" be stored in the database?

> nobody stores user mode in session

That's optimistic: https://github.com/akagadovskiy/ng-admin-jwt-auth/blob/maste...

> > but without the battle-tested implementations. > "I don't know what's wrong but I'm kinda afraid to try".

Battle-tested implementations have dealt with (at least some of) these threats previously. New approaches often miss the lessons of past efforts, leaving themselves vulnerable to old attacks.


> Would this "nonce" in the database?

Only in revoked list=1,2,5,7 etc. Unlike storing all sessions, you only store revoked integers which takes way less space and achieves same revocation you wanted.

> That's optimistic

Nobody should store

> leaving themselves vulnerable to old attacks

Every new line of code is probably a vulnerability. That's life. BTW JWT indeed had some super stupid bug with alg=NONE before, and I would simply throw away "header" from JWT


What I do: I use tokens (rather than cookies), but I don't use JWT, for some of the reasons listed in the post, such as "can't expire" and "data goes stale". Instead, after authenticating a user, I issue a long piece of random (256 bits of random packed into a base64 string) to the user. I use the same string as a redis key whose value is the actual user ID of the authenticated user.

That way the front end can pass the token to the back end, I can authenticate and authorize using the redis data (I could store more data in redis, but instead I hit postgres for any other data about the user, such as admin roles, when needed during the authorization process).

It's true that this doesn't make you invincible to CSRF or XSS - any attacker who goes through the trouble and gets access to the token via MITM (although I only use HTTPS, that's not a guarantee) or by injecting javascript in the webapp itself (through user-editable content from a malicious user), that attacker suddenly has full access to the user's account. Still, it's a pretty reasonable way to deal with session problems.

I also set expiry timeouts on these tokens and can delete them manually if a user wants to end all sessions (say on password change). Deleting by value match isn't super-straightforward in redis, but it's also possible with a bit of LUA.


CSRF isn't about content injection or acquisition of session tokens. I think you probably know that but the way you describe "doesn't make you invincible" I'd say a little more strongly; it doesn't do anything at all to prevent CSRF (or XSS!)


I thought you could include a tamper-proof expiration time in the payload of a JWT token? It also seems like data-staleness could be addressed, perhaps by including a hash of relevant data and invalidating/reissuing a token when the hash changes?


You can include a tamper-proof expiration time in JWT, but you cannot early-expire or extend that JWT easily (you could always pass back a new, extended one transparently).

But in my system, I just keep expiring the redis key for 25 hours from now each time I touch it, so users' authentications expire after 25 hours (after which point they have to go back through username/password or OAUTH, etc). You can easily change 25 hours to 4 days or a month or whatever.


While that sounds fairly similar to most session implementations, I would recommend using a battle-tested implementation rather than using your own, if at all possible.


JWT makes access control super easy/efficient in some cases because you can setup middleware functions to block/allow specific connections/requests just by looking at access rights stored in the JWT token (no need to do database lookups in many cases).

I disagree about using cookies instead of localStorage. Cookies with the HttpOnly flag enabled (as suggested in the article) don't work well in some environments such as hybrid HTML5/native apps (using WebViews) because of cross-origin restrictions - For an app which runs inside a WebView, the cookie will not be sent to the server if your script files are served from the mobile devices' file system - So your server will never get the JWT token in this case. With localStorage (or a Cookie WITHOUT HttpOnly), you can manually read the JWT using JavaScript and send it through - I know this opens you up to XSS attacks but it's a small price to pay.

Most frontend developers accept the fact that if you have malicious third-party code running inside your app's frontend, that's pretty bad news in any case. The fact that the malicious code can access a user's JWT token isn't the worst thing that could happen - At that point, the malicious frontend code could theoretically do anything it wants with your account by hijacking your UI.

The simple solution to mitigate XSS attacks is to serve all your frontend scripts from your own trusted CDNs - When it comes to vulnerabilities, there is always a tradeoff between CSRF and XSS - Personally, I find XSS threats much easier to manage than CSRF (it's a smaller attack surface).

Also, you CAN invalidate JWT tokens - You can change the auth key from the server-side (thereby invalidating the signature of previously issued tokens). Or you can send JWTs with really short expiries (e.g. every 10 minutes) and then renew them on an interval (e.g. every 9 minutes) so that the JWT doesn't expire while the user is still active.

There are a lot of different ways to use JWTs safely. It is not right for someone to say that a technology is bad unless they are aware of all the possible use cases for it.


I am writing my own framework in Scala and I found a similar good article on this topic:

https://stormpath.com/blog/where-to-store-your-jwts-cookies-...

But then, I'm now even more confused as the others here. How exactly am I supposed to secure my REST API now?


Use sessions for client->server and OAuth2 for server->server.


Thanks!


You should probably be using refresh tokens (https://auth0.com/blog/2015/10/07/refresh-tokens-what-are-th...) to invalidate sessions on a change-password event for example.


there was an article on here which I found more in depth than this, about why tokens are a good way to do auth.

Im on mobile, but it was ~6 days ago if someone digs it up. However, I guess I don't understand what the actual argument is.

Vue js sets the header to auth bearer and pulls from local storage. I have a token and I verify the id in the payload, the subject which is usetname, expiration and the issuer.

If we assume this goes over SSL/https what is the attack vector. The other article (and this) basically say someone can run a script and get the token however it is pointed out that if soneone can run arbitrary code on your site or users machine, then you already lost anyway.

What am I missing?


  Somewhat related to this issue, and yet another potential security issue. Like in a cache, the data in a stateless token will eventually 'go stale', and no longer reflect the latest version of the data in your database.

  This can mean that a token contains some outdated information like an old website URL that somebody changed in their profile - but more seriously, it can also mean somebody has a token with a role of admin, even though you've just revoked their admin role.
Umm, if you are storing the roles of a user in a JWT token, I think you are doing things wrong. The point of the JWT token is not to store ALL information of a user. It's simply a way of identifying the user (their ID) and potentially offering an expiration on the token.

Personally, I use tokens to make authenticated API calls but the API still verifies that the user has the required roles to take the specified action. You can then request user data when they login at the same time the token is issued to reduce request volume and then cache any user data locally (should you not want to ping the API server for user data on every request).

Locally they may be displayed as an admin while the cache says so but on the API server, there's no way for them to make such requests if the role has been revoked.

The greatest flaw that this article assumes is that everybody loads their JWT tokens with all sorts of personal info. This is a horrible practice. While theoretically JWT tokens support this, it's by no means a best practice. In essence, he's arguing against an anti-pattern which is already a known anti-pattern.


Please, for quotes, use a > and/or asterisks, but not a leading space. That triggers formatting that doesn’t wrap.

> This is much nicer


How else would you do it if your backend is a REST API and you want to keep it RESTful? JWT seemed like a good solution until I read this.


You would do it by adding a Redis server that stores stateful sessions (mentioned in the article).

I however disagree with most of the points made in the article, and use stateless JWT myself.


Wouldn't that violate the RESTfulness? I thought stateless was one of the criterias.


It depends on how you define your terms. If you think of the RESTful API and the Authentication mechanism as two separate systems, you can have your cake and eat it too.

We use stateful JWT to "fail fast". That is, we can quickly reject invalid authentication, but we still look up the hash in the database before we actually use it. Our systems that do API and Auth are separate enough that the stateful/stateless distinction isn't useful.


People seem to really wiggle around what constitutes state, when it comes to auth/autz and REST.

Some people seem happy with a tiny amount of state to manage user sessions, which makes REST harder.

Other people use tokens of one flavor or another, which may have more security vulnerabilities than conventional sessions, although I'm not convinced.

Shared secret HMAC style is another alternative, although I'm not clear how to make that work with javascript clients in browsers.

Some people just throw the whole authentication question into headers and do basic auth.


The stateless constraint is perhaps the most misunderstood part of REST. Fielding's dissertation states that in a REST system the messages (i.e. requests/responses) must be stateless, but clients and servers are free to keep whatever state they like. What is meant by stateless here is that you don't need additional state than what's described in the message in order to understand the message itself.

For example, a message that's missing the `Content-Type` header, but includes a body, should be rejected because you can't be sure of the body's content type. If you're expected to infer this information, in order to understand the message, the system isn't adhering to the stateless constraint.

Cookies that have session IDs, that are then parsed and mapped to state on the server side, aren't violating the stateless constraint of REST because the message contains all information necessary to understand the message itself.


Yeah, I guess it is. I only use redis for a simple cache and for worker queues. For authentication I use JWT. I store the user permissions inside the token, purely to be used by the client side (for showing/hiding interface elements). Permissions in the backend are over the database. So I tried to minimize the revoke-problem.


Forget this article. He just doesn't like everybody uses JWT instead of cookie in any case. I still think JWS is a good choice for REST API in stateless session. I don't like to setup a redis server. What you need to do if the redis server cannot support so many users? So use JWT to keep stateless is a good choice.


I'm working on a personal project and use JWT for sessions. The main reason I did this is that my understanding is that it makes it much easier to implement sessions on mobile apps. Is this true? If so, should I continue using them? If not, why do I think that, and how can I future-proof my API with mobile apps in mind?


Doesn't matter. JWT can be read on the client, but it's not necessary. From a typical client's point of view, the auth token is just a string. Doesn't matter if it's a JWT or a random string. The difference is on the server side — checking a signature vs. looking up in a database.


I'm not quite sure the author of the article has a solid grasp of JWT, or identity federation in general given that he compares JWT to cookies (it's more like SAML than anything else). I'd highly recommend giving the RFC [1] a once-over to see what the spec is really about.

> The correct comparisons are "sessions vs. JWT" and "cookies vs. Local Storage".

This is somewhat true, but flawed. The better comparison is "SAML vs JWT," or "CAS vs JWT." JWT is a claim assertion standard (most often used for ID claims), and should not be compared with sessions in any way. A JWT (signed by a trusted authority) is a valid way to start a session, or to hold and transmit data for sessionless communication.

> They really aren't [easier to use].

Maybe not compared to cookies, but they definitely are easier than SAML2, which they ought to replace.

> I have yet to see somebody actually explain how JWT is more flexible.

They have flexible claims which require no DTD; SAML does not. Cookies support this too, but they really shouldn't be part of the discussion.

> Server-side expiration is preferable, in fact - it allows your application to clean up session data that it doesn't need anymore

The best part of signed tokens (if you don't mess with revocation) is that you don't remember any data. You perform an identity lookup, authenticate the user, generate and sign the token, and send it off. No need to keep any data around at all, much less handle the complexity of cleaning it up.

> It doesn't, really. There are roughly two ways to store a JWT:

The way JWT solves CSRF is not by the way it's stored; it's by the way it's transmitted in an Authorization header, which can't be done cross-domain and won't be included by the browser (as cookies would). If you're not using JS, you shouldn't be looking at JWT at all; it's useless without it.

> Users don't just block cookies, they typically block all means of persistence.

Unless they're blocking JS (which would render the whole article moot anyway), then there's memory persistence for as long as the browser hasn't refreshed. This is more than enough persistence to realize the benefits of JWT (talking to multiple backends, SPA experience, etc.) Yeah, it's gone when you refresh or navigate away, but some might call that a feature. Just re-authenticate with the JWT provider and keep going.

> JWT tokens are not exactly small.

They're as small as a secure cookie: metadata header + data + signature. That's it. And they don't need to be communicated as part of the URL (though it's deliberately safe to do so), and should not be communicated via cookie (eliminates CSRF benefit).

> They are less secure

Not if they're signed and validated against trusted issuers. Which they should be. Heck, they'll even be encryptable (in a standardized way) soon. [2] Then even the browser they're sent to can't see what they contain unless it has the private key.

> You cannot invalidate JWT tokens

Yes, you can. Use revocation and check with the authority. Just because it's not specified doesn't mean you can't use long-standard methods (see CRL [3]) to achieve your design requirement.

> Implementations are less battle-tested or non-existent

As with any new technology, implementations are also new. Just like I don't have 5 years of experience with Angular 2. And a quick glance at jwt.io will show you that there are plenty of implementations available for a huge swath of languages.

Seriously, read the spec, know your use cases (JWT is not a session replacement, though it could function similarly), and learn the crypto primitives that make this secure (JWT provides verifiable integrity via signatures, not confidentiality (yet) and leaves that to other layers (until JWE)).

[1] https://tools.ietf.org/html/rfc7519

[2] https://tools.ietf.org/html/draft-ietf-jose-json-web-encrypt...

[3] https://www.ietf.org/rfc/rfc5280.txt


> The way JWT solves CSRF is not by the way it's stored; it's by the way it's transmitted in an Authorization header, which can't be done cross-domain and won't be included by the browser (as cookies would). If you're not using JS, you shouldn't be looking at JWT at all; it's useless without it.

This isn't quite true: JWTs may also be transmitted as an access_token URL or form parameter. As such, they are not useless without JavaScript (which is good).

> > JWT tokens are not exactly small.

> They're as small as a secure cookie: metadata header + data + signature. That's it.

They're in a sadly verbose format, which by its nature tends to lead to double-Base64-encoding values. There're a lot of double-quotes and commas, which isn't wonderful. It's not a colossally-wrong format like XML, but it's not great. And it's not terribly readable, despite being somewhat verbose.


Agreed, SAML to JWT is an excellent comparison.

But IMO it is fair to say you can't invalidate JWTs.

More precisely, if you want the ability to invalidate individual JWTs (oops, John's been hacked), then you'll need some kind of per-request check against an authorization server. And if you're doing that, why bother with JWTs in the first place, rather than pack information into the token you might as well pull it from the auth server.

But there are several use cases where you want to - and can easily - invalidate an entire group of JWTs.

For example, we have multi-tenant apps, and it could be you want to invalidate all the JWTs for a single tenant (oops, Fred's Fruit Barn has been hacked). That can be done in different ways, the simplest being that all JWTs issued prior to some date are invalidated.


JWTs do have plenty of valid uses.

I definitely agree with this point, though:

>If you are concerned about somebody intercepting your [anything], you should just be using TLS instead

It's weird to see a lot of devs try to reinvent the wheel and do some kind of half-assed transport encryption when they could just use TLS.


This part:

"In practice, however, it's fairly trivial to replace the session mechanism at a later point, with the only cost being logging out every user once, when you make the transition."

Is not true in terms of needing to log everyone out once. It is pretty easy to write transition code, to accept the old style session and return the new style. You might not be able to transition everyone (if they don't use the session in the time you have your conversion code running), but you will get MOST people, and certainly most active users.


So, I've been approaching JWT as a "proof of login" essentially, to handle authentication across web, mobile apps. The only payload I use is relevant to identifying the user logged in. Session data would be handled by server-side code, though it's still early days for me so I haven't had a use for it yet.

After reading this, I'm wondering if I'm misusing JWT, and should replace it for the use-case of authenticating API calls are coming from an identified user in a client agnostic way?


From the sounds of it, you're essentially using stateful JWT tokens. In that case, I'd recommend using a battle-tested session implementation for your stack of choice instead, if there is one - this rules out implementation errors or overlooked security issues on your end. Security can get pretty tricky.

The exact token scheme you use shouldn't matter for the client. As long as the client supports cookies in some way, it'll just treat it as a dumb blob of text - only the server needs to care about how to interpret the session token.


I'm using actionhero for the backend. To be clear, I'm not concerned about _sessions_ so much as I'm concerned about authenticating all requests. I guess it's just still not clear to me based on the article and your feedback what the flaw is checking a valid JWT in the Authorization header to identify the user making the request? Other than the relative inability to invalidate sessions (ie, only hacky methods for achieving this)


While several points in the article are arguable but I agree not using "JWT for managing user sessions in their web applications". If you need to add extra / custom / unproven mechanisms to invalidate JWT tokens and this defeat the purpose of the simplicity of using Stateless JWT - people are using sticky sessions or session servers to solve the scalability problem of user sessions in web apps pretty well and most frameworks bundled battle-tested libraries to do so long time ago.


my approach: after authentication i'm generating a JWT and send it to the client that stores it in LocalStorage. On the server side I'm using a memcached database that stores a key-value-pair (JWT and some config stuff that shall not be visible on the client side..) for 30 minutes and then deletes it. The JWT is sent with every client request in the Authorization header. A function checks if there is any key-value-pair in the memcached database that matched the JWT (key) and if that JWT is valid. After that it continues or denies the request. The client requests a new JWT after 29 minutes. If the client is offline and doesn't request that new JWT, the old JWT is killed after 30 minutes, anyway. I can't see any other attack vector than XSS - which I'm trying to avoid as hard as I can. But lets face it: IF you have a XSS problem, then you'll have it anyway, with JWT or without. If someone has full access to the JavaScript of your website, he/she can capture any authentication data you are going to send over the wire, unless you use cookies (where you'll have the CSRF problem..).

SO, I think it's pretty safe if you get your XSS protection right.

Opinions? Thank you :)


Postgrest (http://postgrest.com/) uses JWT to switch between database roles.


Except for local storage the information in this post is useless and partially false.


The one thing that I found scary when reading up on JWTs is that there is no way to revoke them. Of course you could check them against a list of revoked tokens on your server, but then your lose the stateless aspect. So the only remaining option to revoke a JWT is the nuclear option, invalidating all JWTs at once.

This seemed like a rather large limitation to me. Related to this, the ability to encode further information in the token, e.g. access rights suffer from the same flaw. If I use the tokens themselves to grant different privileges on a site, I can't revoke those privileges.

I've never used them in practice, this is all just from reading about JWTs. How do people deal with those aspects in practice?


Tokens are created with an identifier, creation time, and expiry time. They are signed.

For web connections I use a renewal token with a long expiry (in the weeks) that is used to ensure we always have a fresh active token (in the hours). You can't get an active token with a refresh token that has a creation time less than a timestamp stored with the login details.

This allows revoking within a few hours, which is good enough for the vast majority of cases. I also maintain a pushable blacklist for emergencies - good UX for this is have the revoke button lead to a "X has successfully been logged out, this may take a few hours to affect all of our services. If it is important that they are logged out immediately click here <Force Immediate Logout>".

For mobile devices which need to limit requests to the server I allow passing a refresh token to most of the services, which will validate it via the server and return an active token with the response.

This works well for the applications I use it in, because I can do instant revokes, but gradual revokes are business case acceptable. Having a token does not allow you to purchase or permanently delete anything. "Super Admin" actions are done with a different system (that only appears integrated to the end user, different DB logins and everything) that requires password validation anyway.

It is not suitable for every application, but it does allow me to operate without inter-service communication for the vast majority of the time.


JWTs can be revoked if you sign them with application_key + some_user_revocation_string.

This is how password reset tokens work in Django, for example. They're signed with the app's secret key + the user's existing password hash. Once the user uses the token to change the password, the token is no longer valid.


Hrrm, now you're in a situation where you're using part of the unverified payload to look up part of the secret before validating the signature and hence the payload. This is a neat idea but it introduces a whole class of potential vulnerabilities. (This is similar to the argument against the algorithm being selected from the unverified payload before being used to validate the signature per the JWT specification.)


However every service now needs access to the list of hashed passwords.


Or access to a service that has access to the hashes/revocation strings. Which puts you in a similar situation to non-JWT scenarios where every service has to phone home to check a token's validity.

I'm not saying all tokens should be made revocable in this way. I'm saying that people claiming "you can't invalidate a JWT" are overstating their case. If you really need to do invalidation, this is one option.


What you've described is literally the same tradeoff you must decide on with caching TTL, but in the arena of credential validity for signed tokens.

In both cases, you're deciding how long something should be valid before it's flushed and must be renewed, or whether you should always check the source.


> How do people deal with those aspects in practice?

In one word: Poorly.

There is no elegant solution outside what you've outlined here. Or: they use stateful JWTs.


The nice thing is that you get quite a bit of middle ground to play with performance. Examples:

* Refresh TTLs that allow for some caching before hitting a DB (revoking). * Using a Bloom filter to revoke to limit the number of affected users, but also bound memory.


So, we should use mint vaseline for session?


1. Mobile sessions are not realiable

2. You dont need to run redis (with service discovery!)

I fail to see cons.


This article seems opinionated without much substance and I disagree with many of the points listed. It also doesn't address using a JWT Token in a Cookie for Web Apps as recommended at:

https://stormpath.com/blog/where-to-store-your-jwts-cookies-...

And ignores usage of refresh tokens: https://auth0.com/docs/refresh-token

    Easier to use
JWT's are simpler when your System is composed of multiple Services as only a single Service needs to issue JWT's and provide Auth Services, all other isolated Services only needs to know how to validate a token and doesn't need other Session State or Auth configured yet are still able to provide protected Services.

    More flexible
JWT's allow for externalized, centralized Auth where the issuing of the Token can be decoupled from validating it. It lets you easily launch new Services offering Protected API's out-of-the-box without needing to configure any Auth or persistent Session state.

    Data goes stale
Services that care about stale data embedded in JWT's should hit the DB using the UserId embedded in JWT's, this is more "live" then accessing it from a Session which is stale from the moment the Session or JWT is created.

    More secure
It's not less secure, and one instance where it can be more Secure if you use RSA as the centralized Auth Service can sign JWT's with its private keys and Services validating tokens with only a public key. So JWT's can be cryptographically verified it's been issued from a central authority with access to the Private Key. Whereas authenticity of Session data is not verified and can be tampered with anyone with access to the session data store. The recommendation is to use Redis which offers weak security since it's not supposed to be accessed externally so uses a simple password which is sent plain-text over the wire.

    Built-in expiration functionality
"This is nonsense, and not a useful feature." Unhelpful Opinionated assertion slinging. Embedded expiration could be a simple constant or implemented from a Custom policy based on the User. Since this is decided by the Issuer this logic only needs to exist in one place.

    Works for users that block cookies 
"Unlikely. Users don't just block cookies, they typically block all means of persistence." Not sure where the article gets its fact checking from, but this is another opinionated assertion not backed by any sources. Cookies are blocked due to privacy issues, whereas Local Storage is used a lot more for providing rich Web App functionality. Disabling Cookies definitely does not also imply disabling Local Storage.

    They take up more space
The space trade-off is due to enabling a more performant, scalable and flexible stateless architecture.

    You cannot invalidate JWT tokens
Another strong assertion that is false. You can include any mechanism you like to invalidate tokens, e.g. you could embed a unique JWT Id (https://tools.ietf.org/html/rfc7519#section-4.1.7) to check against a blacklist loaded in App Servers memory. Your JWT implementation could have an option to "Invalidate all JWT Tokens issued before certain date" which is similar to flushing a Session storage, i.e. all JWT/Sessions created get invalidated. The simplicity and statelessness of JWT's makes it easy to apply custom generic logic.


What's refresh token for?


Facepalm




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: