0

I've been learning about OAuth2, JWT tokens, and refresh tokens.

My understanding of this is:

  1. A user logs in using their credentials.
  2. They are given back an access token (short-lived) and a refresh token (long-lived).
  3. Any requests to API resources uses the access token.
  4. When the access token expires, the refresh token is used to get another one. This avoids the need for the user to re-enter their credentials, while at the same time giving a mechanism to revoke access.

  5. Because of the way it is signed, the access token (JWT) is tamper-proof and can include any claims. Typically tokens are all signed with the same key regardless of the user, which means that you can't boot a compromised user based on access token alone without changing the key and kicking out everyone else.

Given all this, is there anything wrong with simplifying the process as follows?

  1. Store an access token for each user in the database, along with a key used for signing (per user).
  2. When the client sends a token to the server, it includes a header (or similar) with the user id (or a representation of it). This is so that the server can identify the user without decrypting the token first.
  3. The server fetches the key for that user (using the provided id) and decrypts the token with it. If the user id from step 2 has been tampered with, token decryption will fail.
  4. When an access token is compromised, it can be deleted entirely or its related secret changed.
  5. Access tokens can thus be long-lived and there is no need for refresh tokens.

The added effort to store these access tokens in the database is about the same as for storing refresh tokens. The benefit is that the flow is simplified to one authorization mechanism rather than two.

  • "the server can identify the user without decrypting the token first..." - JWTs are not encrypted. – Ahmad Oct 1 '19 at 12:25
  • @Ahmad, JWTs are not encrypted by default but can be encrypted. There is a way to encrypt those. – Bartosz Rosa Oct 2 '19 at 14:40
1

Storing a whitelist of access tokens in a database is a great way to perform access token revocation; if it's not in the DB, don't accept the token. However, this undermines one of the main advantages of JWTs: being able to verify tokens without having to access to a centralised DB. Usually, the short lifespan of access tokens is considered a good enough safeguard to make revocation of access tokens unnecessary. Refresh tokens can be revoked though (by disallowing a particular user from generating more access tokens).

Storing a unique key pair per user is not a great idea. They use much more storage than tokens and therefore take longer to read and write, and are time-consuming and CPU-intensive to generate. It also achieves little in the way of security.

Frequent key rotation is a better idea. Multiple signing keys can be in use simultaneously, with the key identified by either the 'kid' or 'x5t' claim in the JWT header.

  • Thanks for your answer. What you could have explained better is that the token verification from the database must be done per request, which thus adds significant overhead, and is the main flaw in my proposed approach. You did mention the implications, but the fact that it's per request I think is the focal point. I suggest editing to clarify this. – Gigi Oct 3 '19 at 18:24
-1

If you want to identify users on behalf of the access token, you should rather think of OpenID Connect standard. As OAuth2 is an Authorization framework, it is NOT designed for Authentication purposes. There you will be able to use identity tokens which can be retrieved on behalf of request to UserInfo endpoint with access token as Bearer.

I have never meet the solution with storing access token with signature key (not even the access token only). If you would like to revoke the token Authorization Service should implement so-called "Revocation Endpoint" which can be used to revoke tokens.

It is also recommended to use short-lived access-tokens with refresh-tokens only where you can request "refresh" at the backend. If you do not have a backend (i.e. SPA apps) you should not use refresh-tokens (to avoid problems with storing those on client-side) and use so-called "silent-refresh" - where you do request new token on iframe.

  • I am not sure I understood how this answers my question. – Gigi Oct 3 '19 at 18:26
  • My answer says that you should not consider inappropriate solutions if there are already solutions which are a standard. – Bartosz Rosa Oct 3 '19 at 23:02
  • My question was asking whether my suggested alternative was appropriate in the first place, so unfortunately you kind of missed the point there. Also, while I understand the recommendation to stick to best practices when it comes to security, I don't think people should be discouraged from thinking outside the box. – Gigi Oct 5 '19 at 9:27

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.