i'm currently building a WebApp with authentication/authorization to access it and also to access several WebAPI's, all pointing to a Identity Server 4 host. I have followed the official documentation of IdentityServer4 and its demos and for client authentications, token generations, user logging in, API's being called succesfully with tokens, all work fine, apparently, but recently i noticed that after some time of inactivity, the call to the API's start to receive 401 but the client application is still up with the same token.
It's like this:
Now, the problem (after the previous step 4)
What i found out is that the token is expired, Visual Studio output points that out (also checking the token on https://jwt.io/ i can confirm the datetime). Why the same token works fine for the ClientApp while invoking the API doesn't? Do i require to manually generate a new token because of the API's calls?
The configurations i'm using are:
---CLIENT application---
new Client
{
ClientId = "idWebApp",
ClientSecrets = new List<Secret> { new Secret("secret".Sha256()) },
AllowedGrantTypes = GrantTypes.Hybrid,
AllowAccessTokensViaBrowser = false,
EnableLocalLogin = true,
RedirectUris = { "http://localhost:5901/signin-oidc" },
FrontChannelLogoutUri = "http://localhost:5901/signout-oidc",
PostLogoutRedirectUris = { "http://localhost:5901/signout-callback-oidc" },
AllowOfflineAccess = true,
AllowedScopes = new List<string>
{
IdentityServerConstants.StandardScopes.OpenId,
IdentityServerConstants.StandardScopes.Profile,
IdentityServerConstants.StandardScopes.OfflineAccess,
"apiAccess",
},
RequireConsent = false,
}
---API resource---
(Just using simple ctor to initialize with a 'Name')
new ApiResource("apiAccess")
---Custom Claims---
new IdentityResource()
{
Name = "appCustomClaims",
UserClaims = new List<string>()
{
"customRole"
}
}
---Startup code of ClientApp---
services.AddAuthentication(options =>
{
options.DefaultScheme = "Cookies";
options.DefaultChallengeScheme = "oidc";
})
.AddCookie("Cookies")
.AddOpenIdConnect("oidc", options =>
{
options.Authority = "http://localhost:5900";
options.RequireHttpsMetadata = false;
options.ClientId = "idWebApp";
options.ClientSecret = "secret";
options.ResponseType = "code id_token";
options.Scope.Add("profile");
options.Scope.Add("offline_access");
options.ClaimActions.MapUniqueJsonKey("offline_access", "offline_access");
options.Scope.Add("appCustomClaims");
options.ClaimActions.MapJsonKey("customRole", "customRole");
options.Scope.Add("apiAccess");
options.GetClaimsFromUserInfoEndpoint = true;
options.SaveTokens = true;
options.TokenValidationParameters.RoleClaimType = "customRole";
});
Why the same token works fine for the ClientApp while invoking the API doesn't?
Two things:
Once issued a JWT token can't be changed. By default the token expires after 3600 seconds.
The cookie has its own expiration logic. This means that it expires at a different time, unrelated to the expiration time of the access token, and also can be kept alive because the cookie can be updated, unlike the JWT access token.
For offline_access
you require to obtain a new access token, using the refresh token. As explained here.