I am using Authorization Code flow for one of my Identity Server 3 clients and it is configured as follows:
ClientId = "tripgalleryauthcode",
ClientName = "Trip Gallery",
Flow = Flows.AuthorizationCode,
AllowAccessToAllScopes = true,
RequireConsent = false,
// redirect = URI of our callback controller in the IOS application
RedirectUris = new List<string>
{
"somecallbackuri"
},
ClientSecrets = new List<Secret>()
{
"somesecret"
},
// refresh token options
AccessTokenType = AccessTokenType.Jwt,
AccessTokenLifetime = 120,
RefreshTokenUsage = TokenUsage.OneTimeOnly,
RefreshTokenExpiration = TokenExpiration.Absolute,
AbsoluteRefreshTokenLifetime = 360,
As you can see, It is configured to expire the access token in 2 minutes and the refresh token in 6 minutes. I did this because I wanted to try to debug the problem in a smaller time frame instead of the one that I use in production : 15 days for refresh token, 1 hour for access token. We noticed that for some reason, refresh token issued today doesn't work tomorrow. That is why I decided to decrease the times and this is what happened:
I have noticed even a bit more. What happens is that 2 minutes after the access token expiration I get the 400 error. It says refresh token is invalid.
This is the log from Identity Server.
w3wp.exe Information: 0 : 2016-11-23 10:56:15.802 +00:00 [Information] Start token request
w3wp.exe Information: 0 : 2016-11-23 10:56:15.802 +00:00 [Information] Client secret id found: "tripgalleryauthcode"
w3wp.exe Information: 0 : 2016-11-23 10:56:15.802 +00:00 [Information] Client validation success
w3wp.exe Information: 0 : 2016-11-23 10:56:15.802 +00:00 [Information] Start token request validation
w3wp.exe Information: 0 : 2016-11-23 10:56:15.802 +00:00 [Information] Start validation of refresh token request
w3wp.exe Warning: 0 : 2016-11-23 10:56:15.802 +00:00 [Warning] "Refresh token has expired"
"{
\"ClientId\": \"tripgalleryauthcode\",
\"ClientName\": \"Trip Gallery\",
\"GrantType\": \"refresh_token\",
\"RefreshToken\": \"d12f50289e5cded13082de989a64ac01\",
\"Raw\": {
\"grant_type\": \"refresh_token\",
\"refresh_token\": \"d12f50289e5cded13082de989a64ac01\"
}
}"
w3wp.exe Information: 0 : 2016-11-23 10:56:15.818 +00:00 [Information] End token request
w3wp.exe Information: 0 : 2016-11-23 10:56:15.818 +00:00 [Information] Returning error: invalid_grant
I'd really like to know what causes that behavior and what causes my expiration token to expire before is deadline.
The member must reauthorize your application when refresh tokens expire. When you use a refresh token to generate a new access token, the lifespan or Time To Live (TTL) of the refresh token remains the same as specified in the initial OAuth flow (365 days), and the new access token has a new TTL of 60 days.
When ACCESS_TOKEN expires you need to call another api with REFRESH_TOKEN to get new ACCESS_TOKEN. The client application can get a new access token as long as the refresh token is valid and unexpired.
If you look in the dashboard application settings, you can see the Refresh Token expiration time. By default, it is 720 hours (2592000 seconds). Since the error message says inavlid_grant , it may be possible that the application is not configured to accept Refresh Token grants.
The refresh token is set with a very long expiration time of 200 days. If the traffic to this API is 10 requests/second, then it can generate as many as 864,000 tokens in a day.
The reason why this happens is because there's a clock skew feature built into JWT that protects you from out of sync clocks. Without this you might run into problems where tokens are not valid yet.
The default value for this is 5 minutes - this affects the access_token
as well as the refresh_token
.
You can change this value with JwtBearerOptions.TokenValidationParameters.ClockSkew
, in IdentityServer4.AccessTokenValidation.CombinedAuthenticationOptions
This behaviour is also specified in the official JWT Draft:
Implementers MAY provide for some small leeway, usually no more than a few minutes, to account for clock skew. Its value MUST be a number containing an IntDate value. This claim is OPTIONAL.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With