DEV Community

Refresh JWT with Refresh Tokens in Asp Net Core 5 Rest API Step by Step

Mohamad Lawand on January 25, 2021

Hello friends, In this article I will be showing you today How to add refresh tokens to our JWT authentication to our Asp.Net Core REST API Some...
Collapse
 
walvarez00 profile image
Walter Alvarez

Hi Mohamad, Im using v8-refreshtokenswithJWT and when I trY to RefreshToken I have always Token has expired please re-login. This behavior succeds in line:

            var tokenInVerification = jwtTokenHandler.ValidateToken(tokenRequest.Token, _tokenValidationParams, out var validatedToken);
Enter fullscreen mode Exit fullscreen mode

Then the software dont continue

Can you help me please. What can I do for fix it?

Thanks

Collapse
 
walvarez00 profile image
Walter Alvarez

The project works if I change ValidateLifetime to false

This is a good solution?

Thanks

Collapse
 
moe23 profile image
Mohamad Lawand • Edited

Hi Walter, there is a small bug related to regeneration of the refresh token. I will push a fix for this within this week. We should always keep it to true

Thread Thread
 
walvarez00 profile image
Walter Alvarez

Thanks Mohamad

Thread Thread
 
afaggit profile image
afagGit

Hi Walter, hi Mohamad,

I'm still facing the same issue as described above. "jwtTokenHandler.ValidateToken" always throws an token expires exception. Is the bug fixed already?

Thank you and greetings.

Alex

Collapse
 
grandsilence profile image
Grand Silence • Edited

Some fixes for the article:

  1. If you need lifetime of token less than 5 mins, add ClockSkew property in Startup.cs:

    var tokenValidationParameters = new TokenValidationParameters {
        ValidateIssuerSigningKey = true,
        IssuerSigningKey = new SymmetricSecurityKey(key),
        ValidateIssuer = false,
        ValidateAudience = false,
        ValidateLifetime = true,
        RequireExpirationTime = false,
    
        // Allow to use seconds for expiration of token
        // Required only when token lifetime less than 5 minutes
        // THIS ONE
        ClockSkew = TimeSpan.Zero
    };
    
  2. Don't forget to use UTC instead of local time. You will need to fix method GenerateJwtToken:

      var refreshToken = new RefreshToken(){
            JwtId = token.Id,
            IsUsed = false,
            UserId = user.Id,
            AddedDate = DateTime.UtcNow,
            // INVALID DATE, USE UTC
            // ExpiryDate = DateTime.Now.AddYears(1),
    
            // Now it's correct
            ExpiryDate = DateTime.UtcNow.AddYears(1),      
            IsRevoked = false,
            Token = RandomString(25) + Guid.NewGuid()
        };
    
Collapse
 
moe23 profile image
Mohamad Lawand

Thanks a lot Grand for these fixes, I am planning to add them this week.
If you want you can add a PR on the GitHub repo and I will merge them t

Collapse
 
rcpokorny profile image
Bob Pokorny, MBA

Hi Mohamad!

I have been following the currently 3-part series and continue to enjoy every video. I am currently experiencing a problem with the token not expiring and I think it is happening on Validation #3.

I'm finding that the expiryDate and DateTime.UtcNow values are too far apart to even expire. For example, at the time of running, my expiryDate value = '03/09/21 8:56:38 am' and my DateTime.UtcNow = '03/09/21 2:57:06 pm'.

I did end up using you exact code in GIT to make sure I'm getting the same results. Still no resolution. Then I started thinking, I am using zScaler to log into our network and wondering if that is having problems with date/time. However my expiryDate value is my local and accurate time.

Any ideas to why I cannot get my token to expire?
Thanks,
Bob

Collapse
 
moe23 profile image
Mohamad Lawand

Hi Bob,

Thank you for your feedback and comment, I will push an update to git repo to fix.

I apologise for the delay.

Collapse
 
shawld2 profile image
Lee Shaw

Hi Mohamad, love the article!
Should the accessToken expire after 30 seconds? And when it does how is this handled? Using Swagger the token doesn't seem to be 401ing when i'm accessing the api/todo.
I have downloaded v8.
Thanks in advance.
Lee

Collapse
 
moe23 profile image
Mohamad Lawand

Hi Lee, I think you can configure the token to for 5 min and then it can expire and use the refresh token to get a new one. There is a bug in the code in V8. I will be pushing a fix this week for it

Collapse
 
avery_cat profile image
aVery_cat

Hey I have a question, great tutorial btw, thanks for making it.
If user wants to refresh access token, it also gets new refresh token, shouldn't we just remove the old refresh token instead of marking it as used?

Collapse
 
moe23 profile image
Mohamad Lawand

For compliance reason you might keep them for a certain amount of time and then remove them.

Collapse
 
zujaj profile image
Zujaj Misbah Khan • Edited

How did you define the ExpiryTimeFrame in JWTConfig model?
After the token expires, how would the automatic re-authentication take place when you're pointing to the login endpoint again?
Does it mean that we have to store the login info in our app? Please elaborate if i misunderstood.

Collapse
 
wangzhe66369 profile image
wangzhe66369

Hi Mohamad!
I have a question, why use RefreshToken, it seems that only using Token can also refresh the token.
Thanks in advance.
Zhe

Collapse
 
annguyen209 profile image
An T. NGUYEN

Refresh token is similar to a backup key to get back new token in case it is expired or lost. You are sending the token over the internet many times so it "maybe" stolen.
That why we keep token expiration time is shorter a lot to the refresh token.

Collapse
 
wangzhe66369 profile image
wangzhe66369

Thank you for your answer.
I understand that the purpose of JWT is to not store data on the server side. Now that the RefreshToken must be stored on the server side, does it violate the purpose of JWT? I feel that this approach is very similar to Session

Collapse
 
candede profile image
candede

hi Mohamad, thanks a lot for this series; truly great work.. I had an issue similar to some others where RefreshToken was not working since the token parameter validations enforce ValidateLifeTime and the only time you want to refresh the token after it's expired. So I have added another TokenValidationParams only to be used during Refresh Token creation and set the ValidateLifetime to false

var refreshTokenValidationParams = new TokenValidationParameters
{
ValidateIssuerSigningKey = true,
IssuerSigningKey = new SymmetricSecurityKey(key),
ValidateIssuer = false,
ValidateAudience = false,
ValidateLifetime = false,
RequireExpirationTime = true
};

services.AddSingleton(refreshTokenValidationParams);

I've also updated the AuthManagementController constructor to call refreshTokenValidationParams

public AuthManagementController(UserManager userManager, IOptionsMonitor optionsMonitor, TokenValidationParameters refreshTokenValidationParams, BeanDataContext beanDataContext)

This fixed my issue but I dont know if this is the most elegant solution or a good solution at all. So I wanted to put here in the hope that someone will tell me if there is a better way of doing it. Thanks a lot for your time and efforts to put this series together

Collapse
 
moe23 profile image
Mohamad Lawand

Thank you very much for your feedback, maybe you can push your code to the repo and will review it there so other people will be able to benefit

Collapse
 
muslimcoder profile image
Omid tavana

tnx dear Muhmad. that was awesome

Collapse
 
muhammadshahidkhanafridi profile image
Muhammad Shahid Khan Afridi

Hi Mohamad Lawand,
I did not find any Logout functionality here. can you please implement it or can you help via a comment for logout functionality in the same "AuthManagementController" controller?

Collapse
 
mehrdad_davoudi profile image
Mehrdad Davoudi

Hi Mohamad, Thank you for great article.
If you have time can you please add another part for 2fa authentication for web api.
there isn't any good article about that part. or I didn't find...

Collapse
 
moe23 profile image
Mohamad Lawand

Thank you for your kind feedback will add this topic to my list

Collapse
 
said96dev profile image
Saeed

Hello, I have a question about JWT, if the server can't store or remember the token after req, so how can the server check if the token sent by the client is valid or hasn't been modified

Collapse
 
victordevmetro profile image
VictorDevmetro

Every time I call a RefreshToken API I get this message: "Token has expired please re-login". (I'm using lastest codes)

Collapse
 
a7med2020 profile image
a7med2020

Edit TokenValidationParams Like @candede said

Collapse
 
vbjay profile image
Jay Asbury • Edited

NEVER use datetime. ALWAYS use DatetimeOffset. You get timezone handling abd not confusion between a date over here and a date over there.

Collapse
 
mohammadmkh profile image
Mohammad-m-kh

Hi, how is it possible to get current user in controller?