ASP.NET Core 2.2 REST API #13 — Refreshing JWTs with Refresh Tokens
Up Next: Running in Docker
Let’s change our IdentityController
in order to issue refresh tokens.
Let’s add one more property to our "JwtSettings"
, called "TokenLifetime": "00:00:45"
(45 seconds — just for testing, you should have at least 5 minutes for a production scenario). Let’s update our JwtOptions
to include this token lifetime property. we will update our MvcInstaller
to use some new token validation parameters and add a singleton TokenValidationParameters
:
The next step would be to alter our AuthSuccessResponse
to include a refresh token, as well as our AuthenticationResult
class, making sure to include the actual data back, on the /register
and /login
endpoints.
We can go ahead and create a new endpoint /api/v1/identity/refresh
using our already-known strongly typed route best practises, creating contract objects on demand:
Refreshing the token
We’re first going to create a helper method that is going to return who is the one that owns the token( ClaimsPrincipal
)while also checking if the JWT is signed with a secure algorithm.
Let’s create a new RefreshToken
domain class. We will use this for the database as well.
The Dates are there for auditing purposes and the JwtId
is the JWT that this refresh token is bound to.
You might want to invalidate all the refresh tokens for example, when the user changes his email.
Add the table to EF by using a DbSet<RefreshToken>
and then add and apply the new migration.
The next part is lengthy, but it contains all the checks we need to do about token validity:
- JWT authenticity, validity, security algorithm and claims principal check
- Check that the JWT is expired (not mandatory, but we will use this to have some stricter security constraints — the user could just use the previously issued token)
- Check if the refresh token is bound to the current JWT token id
- Check if the refresh token is actually saved in the database
- Check if the refresh token is not expired, used or invalidated
After all these checks we can just flag the token as Used
, save it to the database and issue a new token pair for our user.
The final part would be to update our GenerateAuthenticationResultForUserAsync
method to issue and save refresh tokens as well.
We just hardcoded the 6 months expiry date for the refresh token, but you can make this configurable as well.
You can check that if you wait 45 seconds for the first token to expire, sure enough, you get a new token pair back.
If you try to do some illegal operation, like re-use the previous refresh token, you get the corresponding error message:
Up Next: Running in Docker
Code is available on Github and the instructional videos are located on YouTube.
Keep Coding