In OAuth implementation, Authorization/Resource server assigns an AccessToken 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
oauth.net
oauth0.com
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 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) thanAccessToken
(could be 1-3 hours).-
When
AccessToken
expires, the webapp/client would hit/api/auth/token
endpoint withRefreshToken
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 newAccessToken
without any user interaction involved.
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 incomingRefreshToken
in the in-memory cache or database. - If found, the system issues a new
AccessToken
else invalidates the request.
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.
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 (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 newRefreshToken
that system generates for each login request.When system recieves a request to refresh the
AccessToken
. System will verify ifiat
value of incomingRefreshToken
matches the currentiat
against the current user in the database.If both
iat
values match then system issues new pair ofAccessToken
andRefreshToken
otherwise401
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:
Short Expiry times
The straightforward stateless solution enforces the use of short expiry times for bothAccessToken
andRefreshToken
like 10min expiry forAccessToken
and 1hr expiry forRefreshToken
. This simply reduces the time for any malicious activity if occurred.User-Defined Secret
For each user, use a different secret to sign theRefreshToken
JWT likesecret = ENV.secret + user.password
while generating theRefreshToken
. At any time, ifRefreshToken
of a particular user is compromised, ask that user to reset theirpassword
and all old RefreshTokens issued to that user would be revoked automatically.
See implementation: here
I hope this helps 🙂.
Top comments (1)
Helpful post, thanks! 👌