24

I've read that JWT tokens are stateless and you don't need to store the tokens in the database and that this prevents a look up step.

What I don't understand is that according to RFC 7009 you can revoke a token. Let's say I have a web site with a Sign Out button that calls a token revocation flow like in RFC 7009. If no tokens are stored in the database, what's to prevent the client from using a token that's been revoked?

If I Sign Out, I would expect to have to Sign In again. Is it solely the client's responsibility to clear the token locally?

Do you need to store the refresh token in a database or store to implement RFC 7009?

9
  • 5
    OAuth and JWT are different things.
    – ThoriumBR
    Nov 9, 2022 at 0:00
  • @ThoriumBR good point. Are they compatible? Have I conflated things that I shouldn't have?
    – Gilles
    Nov 9, 2022 at 0:12
  • 6
    JWT is stateless, OAuth is stateful. JWT is self-contained, OAuth needs a backend. Revoking JWT is complex and not always possible, OAuth is trivial. JWT are faster to validate (no database access needed), OAuth requires a database.
    – ThoriumBR
    Nov 9, 2022 at 0:16
  • 2
    You could have a database of revoked tokens, that would be significantly smaller than a database of valid tokens. Nov 9, 2022 at 19:50
  • Size isn't typically the problem for the state -- it's creating a single point of failure/overhead for your auth
    – cjol
    Nov 10, 2022 at 21:45

5 Answers 5

48

RFC 7009 is about OAuth, not JWT. You are mixing two different technologies: JWT and OAuth. This question on StackExchange summarizes it well.

JWT is a token format. It defines the fields, the signing protocol, the encoding. OAuth is an authorization protocol that can use JWT or not, depending on the developer.

It's not easy to revoke a JWT, because they are stateless, self contained and don't use a database. Revoking a JWT would require storing some value on a database, looking at that value at each request, and that would look a lot like OAuth but with the overhead of mixing the two together.

3
  • 3
    This is really the best answer since it answers the question, without going into detail on JWT and OAuth tokens. Most of the other answers add more information/context, but make assumptions which result in incomplete explanations and confusing answers.
    – Buurman
    Nov 9, 2022 at 14:34
  • 4
    because JWTs are stateless, the only way to revoke them is with a backing store, in this way the system becomes stateful. The problem is that all services will have to have access to this revokation list to check if the token has been revoked, instead of implicitly trusting the token. Good news is you only need to store the revoked tokens, not all of them, and only until the token was going to expire anyway, making this an efficient compromise. Nov 10, 2022 at 10:04
  • @ChrisSchaller: You only need to search the revoked tokens, but you need to store all of them (until expiration), or else you won't be able to insert into the revocation list.
    – Ben Voigt
    Aug 17, 2023 at 22:03
19

Do you need to store the refresh token in a database or store

Leaving aside the rest of your question: generally, yes. JWTs need to be short-lived, specifically because there's no good way to revoke them; if an attacker gets one, they'll generally have access until it expires, so the expiration needs to be soon. To accommodate this, but avoid people needing to log in again constantly, we have refresh tokens. A refresh token, by its very nature, is access-equivalent to a JWT (you can exchange it for a new JWT) but long-lived, so of course the server needs to store a list of which refresh tokens are valid (and for which user/session), within which table the supplied refresh token is looked up upon use (but only when refreshing the JWT, not on every request). The server also needs to delete from the DB (or mark as invalid) the refresh token upon the session ending (by explicit logout, session timeout, remote session revocation, etc.).

The refresh token is generally just a secure random byte string (usually HEX- or Base64-encoded), same as a conventional session/access token. Really the only major difference from a session token is that the session token is used to look up the user/session on every request, whereas a refresh token only needs to do that when the JWT is near or past its expiration. People sometimes add additional protections, such as making refresh tokens single-use (assigning a new one whenever one is used) and/or checking for suspicious use of them (e.g. if the token was issued to a British IP address and then used from a Russian one, that might be suspicious enough you'd force login again rather than respecting the token), but you technically can do similar things with session access tokens too.

9

Providing some context, based on ThoriumBR's answer:

Tokens can be either opaque or structured (see here for a short description in the context of OAuth).

An opaque token can be used to implement server side sessions, where the session data are held at the server side and the token functions as a reference to them. An HTTP cookie can be an opaque token.

A structured token can be used to implement client side sessions, where the server does not hold any session data; all the data required to reconstruct the session is held at the token. An example of a structured token is JWT.

Server side sessions are called stateful sessions. Client side sessions are called stateless sessions.

A session can be invalidated in three ways:

  1. client deletes the session token
  2. session token expires
  3. session token is revoked at the server side, anytime before it expires (if at all)

Revoking requires server side state (storing which token is valid and/or which is not), that by nature contradicts with the concept of (stateless) client side sessions.

9
  • While you make a good effort to add some context to ThoriumBR's answer that might help somebody understand how OAuth tokens and JWTs are different (especially given that OAuth tokens are frequently JWTs), the part about server side sessions and client side sessions seems to skip a few things. Both opaque and structured tokens can be used to implement either server side or client side sessions. Every session that holds data is stateful, it is the server (the authorization server, not necessarily a resource server) that is stateless.
    – Buurman
    Nov 9, 2022 at 14:44
  • @Buurman how can you implement client side sessions with opaque tokens?
    – user284677
    Nov 9, 2022 at 14:45
  • You simply store the data you want to store clientside, in clientside storage, linked to the opaque token. You don't need to store it in the actual JWT.
    – Buurman
    Nov 9, 2022 at 14:50
  • @Buurman So how will the server retrieve the session data from the client side?
    – user284677
    Nov 9, 2022 at 14:54
  • 1
    Why would the server need to retrieve the data? If you want to send it to the server (say, as filter option for a GET call) you can just send it along in the request. If you want to save part of it (say, a persistent preference) you can just POST it to a relevant endpoint. But you can easily keep most (if not all) data clientside only. Note, I'm not saying this is good for every situation, or even my personal preference: I'm just saying it's a somewhat common variation. Think of mobile single player games that have you login but store your progress clientside.
    – Buurman
    Nov 9, 2022 at 15:03
5

JWT tokens cannot be revoked easily unless you check the token against an online database.

However, one option that you can use with JWT is instead of storing active tokens in the database, the database can store revoked token instead.

Storing a list of revoked tokens instead of active tokens has the benefit of making your revocation database being much smaller and simpler than if you store active tokens, so the revocation list can just be stored (and cached) in-memory or with an adjacent in-memory database like Redis. You can imagine a distribution mechanism in which a relying party that needs immediate revocation can subscribe to be notified by the auth/identity server whenever a token is revoked.

The smaller size of revocation list can make it easier to scale out a revocation database compared to active session database. The downside of keeping a revocation database is of course that you lose two of the biggest advantage of JWT, which is simplicity and the ability to verify tokens offline, so this kind of revocation mechanism is rarely used.

The only place where I've seen revocation list is widely used is x509 certificate (i.e. certificate used for TLS connection and S/MIME emails). x509 is not exactly the same as JWT, but x509 uses a signed token authorisation/certification that is functionally quite similar to JWT. In fact, x509 actually has three revocation mechanisms: CRL, OCSP, and Certificate Transparency Log, all of which can have parallels to how you'd implement a revocation mechanism in JWT.

1
  • 1
    You can store even less, if you don't need to support "revoke a single session for a particular user" but only "revoke all currently-outstanding tokens of this user". Just store one "global logout" timestamp per user and compare the JWT issuance date to that "global logout", accept only tokens issued after the global logout.
    – Ben Voigt
    Nov 9, 2022 at 16:20
0

Another option that I haven't seen mentioned, is storing a UUID claim in the token, then using that UUID in your database. After decoding the JWT, you can do a lookup in your database for that UUID and check the revocation status.

4
  • 1
    that doesn't actually help at all... typically Systems using JWT either use short revocation times, and or revocation propagation / notification. just look at how kerberos works, in essence it works the same as most JWT systems.
    – LvB
    Aug 17, 2023 at 14:20
  • @LvB Revocation times? That's just an expiration - not revocation. Revocation would be an explicit action, not something based on some kind of expiration or workflow. I also don't see what propagation or notifications has to do with revocation. Aug 17, 2023 at 19:20
  • expiration is just another type of revocation. just one explicitly set at the time of creation. Propagation would be when 1 revoke causes other revokes (typically on the client). and notification would be when a revoke gets communicated to registered servers as a service message. and a workflow is inherently a set of explicit actions... understand it with that additional information? if not, what part do you not understand (I would be happy to try and explain it)
    – LvB
    Aug 21, 2023 at 15:20
  • 1
    @LvB I understand what you're saying now - all standard workflows. And upon reading OP's original question, I realized my post was regarding addressing explicit revocation - not standard revocation workflows, as you're describing and OP was actually inquiring. Aug 21, 2023 at 16:28

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .