I've been learning about OAuth2, JWT tokens, and refresh tokens.
My understanding of this is:
- A user logs in using their credentials.
- They are given back an access token (short-lived) and a refresh token (long-lived).
- Any requests to API resources uses the access token.
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.
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?
- Store an access token for each user in the database, along with a key used for signing (per user).
- 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.
- 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.
- When an access token is compromised, it can be deleted entirely or its related secret changed.
- 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.