JWT token silent renew breaks and causes crash on React template with authentication
See original GitHub issueDescribe the bug
The JWT silent renew in the React template with authentication can fail in some scenarios. What happens is the token is listed as expired (user.expires_in is negative and outside the 5 minute clock skew grace period). As a result, the API request fails with a 401, the token is never renewed, and the user can no longer get into [Authorize] marked areas. The only way to solve this I found (and the workaround isn’t even confirmed), is to explicitly press the logout button and restart my application (presumably to reset authentication/authorization on the client side SPA).
If you don’t explicitly log out, this issue will persist even on restarts of the ASP.NET application presumably because it’s a client side issue. There are a lot of steps to the below so some may or may not actually contribute to the issue but it is a consistent repro.
To Reproduce
- Create a new React based ASP.NET application with Individual User authentication
- Reduce the AccessTokenLifetime parameter by modifying the call .AddApiAuthorization to:
.AddApiAuthorization<ApplicationUser, ApplicationDbContext>(opt =>
{
foreach (var c in opt.Clients)
c.AccessTokenLifetime = 65;
});
- The default is an hour but that’s way too long to repro.
- Start the application, register a new account and let it auto-login for you
- Now explicitly log out
- Then login again with your newly created account and make sure to tick the Remember Me box.
- Now stop the application.
- Wait for at least 65 seconds (ie. wait until the JWT access token expires).
- Start the application again with debugging on (if you want to be able to see the expired token live forever; see the last image in this report)
- Wait for 5 minutes while the clock skew grace period is consumed.
- Try to access the Fetch Data page which requires authentication/authorization.
Expected outcome: You get to the Fetch Data page with a renewed JWT. Actual outcome: A crash with a JWT that hasn’t and apparently won’t renew.

You can break into AuthorizeService.js and inspect the user value to see that the token is expired. You can actually see the token work and count more and more negative until it gets to 300 at which point it’ll then fail.:

Further technical details
- ASP.NET Core 3
- VSCode
.NET Core SDK (reflecting any global.json): Version: 3.0.100 Commit: 04339c3a26
Runtime Environment: OS Name: Windows OS Version: 10.0.18363 OS Platform: Windows RID: win10-x64 Base Path: C:\Program Files\dotnet\sdk\3.0.100\
Host (useful for support): Version: 3.0.0 Commit: 7d57652f33
.NET Core SDKs installed: 3.0.100 [C:\Program Files\dotnet\sdk]
.NET Core runtimes installed: Microsoft.AspNetCore.All 2.1.13 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.All] Microsoft.AspNetCore.App 2.1.13 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App] Microsoft.AspNetCore.App 3.0.0 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App] Microsoft.NETCore.App 2.1.13 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App] Microsoft.NETCore.App 3.0.0 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App] Microsoft.WindowsDesktop.App 3.0.0 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]
To install additional .NET Core runtimes or SDKs: https://aka.ms/dotnet-download
Issue Analytics
- State:
- Created 4 years ago
- Comments:18 (5 by maintainers)

Top Related StackOverflow Question
You can work around it quickly in the meantime by triggering a silent sign in for your user when you receive an expired token.
While delay isn’t ideal, it does stop the site crashing.
Unfortunately when getting our user we don’t appear to get the refresh token. Otherwise I’d look at modifying startup.cs, and creating a new tokenController as per https://www.blinkingcaret.com/2018/05/30/refresh-tokens-in-asp-net-core-web-api/
Thanks for contacting us. We’re moving this issue to the
.NET 8 Planningmilestone for future evaluation / consideration. Because it’s not immediately obvious that this is a bug in our framework, we would like to keep this around to collect more feedback, which can later help us determine the impact of it. We will re-evaluate this issue, during our next planning meeting(s). If we later determine, that the issue has no community involvement, or it’s very rare and low-impact issue, we will close it - so that the team can focus on more important and high impact issues. To learn more about what to expect next and how this issue will be handled you can read more about our triage process here.