Refresh Tokens
Tags: jwt, authorization, oauth2, authentication
Published: 2022-01-01 23:20:38

In OAuth implementation, **Authorization/Resource** server assigns an [AccessToken](https://oauth.net/2/access-tokens/) to each successfull user session. `AccessToken` is used by the client to make requests to the resource server.

**RefreshToken** is issued to the client by the authorization server to obtain a new `AccessToken` when the current `AccessToken` becomes invalid or expires or to obtain additional AccessTokens with an identical or narrower scope. Basically, `RefreshToken` provides the clients with a smooth experience where users are not required to repeat login step or some other authentication flow in order to get new `AccessToken`.

References
[IETF](https://datatracker.ietf.org/doc/html/rfc6749#section-1.5)
[oauth.net](https://oauth.net/2/access-tokens/)
[oauth0.com](https://auth0.com/blog/refresh-tokens-what-are-they-and-when-to-use-them/)

### How to use Refresh-Token?

- After each successfull authentication request, Authorization/Resource server must generate 2 JWT tokens (AccessToken , RefreshToken). 
> I talk here with [JWT](https://datatracker.ietf.org/doc/html/rfc7519) specification under consideration but tokens can be either JWTs or some other format of your choice. Its an implementation decision and not a topic to emphasize-on in this post.

- Client will save both of the JWT tokens in the browser at some safe place.
- `RefreshToken` JWT would have longer expiry (maybe 1 day) than `AccessToken`(could be 1-3 hours).

- When `AccessToken` expires, the webapp/client would hit `/api/auth/token` endpoint with `RefreshToken` in request payload. 
> _**/api/auth/token**_ is supposed to issue new AccessTokens.
Client does this silently without alerting the user.

- The system will verify the `RefreshToken` and issue a new `AccessToken` without any user interaction involved.

![refresh-tokens](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/bc0ossilvir3ab6mrlz0.jpeg)

### RefreshToken Revocation

RefreshToken JWTs usually remain valid for longer durations like 1 day, 1 week or so and there is a chance that token could be compromised and misused beyond the user logout action if unexpired. To mitigate this potential threat, there should be some mechanism in place to invalidate the revoked but unexpired JWTs.

Some techniques are mentioned below:

#### JWT Whitelist

Here, the system maintains a whitelist of active RefreshTokens in some in-memory cache or database.
- Every time a new `RefreshToken` request comes, the system looks for incoming `RefreshToken` in the in-memory cache or database.
- If found, the system issues a new `AccessToken` else invalidates the request.

references: [1](https://www.izertis.com/en/-/refresh-token-with-jwt-authentication-in-node-js), [2](https://www.bezkoder.com/jwt-refresh-token-node-js/), [3](https://www.youtube.com/watch?v=ssypjWFdD4E&ab_channel=yoursTRULY)

#### JWT Blacklist

Here, the system maintains a blacklist of old/revoked refresh tokens in some in-memory cache or database. Revoked Tokens live on the blacklist until their expiry time is reached. 
- Every time a new refresh token request comes, the system looks for incoming `RefreshToken` in the in-memory cache or database.
- If found, that means, the incoming `RefreshToken` is revoked and the system invalidates the request.

references: [1](https://auth0.com/blog/denylist-json-web-token-api-keys/), [2](https://auth0.com/docs/security/tokens/refresh-tokens/refresh-token-rotation#automatic-reuse-detection), [3](https://stackoverflow.com/a/40385939/8823192)

#### Unique Claims
Every JWT has a claims list with it that includes information provided by user (`email`, `name`) as well as some attributes required by [JWT Specification](https://datatracker.ietf.org/doc/html/rfc7519#page-8) (`iat`, `sub`).
You can use any claim out of the JWT specification list to ensure token's authenticity. Use below technique:
- Choose a token claim that is always unique at the time of token issuance.
 > JWT `iat` is best option as its a unix time stamp.

- Introduce a new field in your `User` database table where system will save the value of that claim for each new `RefreshToken` that system generates for each login request.
- When system recieves a request to refresh the `AccessToken`. System will verify if `iat` value of incoming `RefreshToken` matches the current `iat` against the current user in the database.
- If both `iat` values match then system issues new pair of `AccessToken` and `RefreshToken` otherwise `401` throws exception.

#### Some Stateless techniques

In the above 2 methods, database queries are involved to check the JWT revocation and this makes the token stateful. But depending on the severity of the JWT compromise that one foresees, there are many techniques out there to avoid any unwanted activity using stateless JWTs. 
2 of them described below:

1. **Short Expiry times**
The straightforward stateless solution enforces the use of short expiry times for both `AccessToken` and `RefreshToken` like 10min expiry for `AccessToken` and 1hr expiry for `RefreshToken`. This simply reduces the time for any malicious activity if occurred.

2. **User-Defined Secret**
For each user, use a different secret to sign the `RefreshToken` JWT like `secret = ENV.secret + user.password` while generating the `RefreshToken`. At any time, if `RefreshToken` of a particular user is compromised, ask that user to reset their `password` and all old RefreshTokens issued to that user would be revoked automatically. 
See implementation: [here](https://www.youtube.com/watch?v=UA0AIkjI85c&ab_channel=BenAwad)

I hope this helps 🙂.