Search code examples
authorizationidentityserver4access-token

Identity Server 4 token expiration Api vs ClientApp


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:

  1. Launch browser with debugging
  2. Login with some user
  3. Go to a view that calls one API to retrieve data for it
  4. Keep navigating and testing, and everything else works fine

Now, the problem (after the previous step 4)

  1. Stop debugging but keeping the browser up and running (keeping the cookies)
  2. Changing code, implementing new stuff (basically passing some time)
  3. Launch debug again
  4. Using the same sessions/cookie on the already open browser, trying to navigate on the application works fine and does not required new login
  5. Navigating to a view that will call the API using the current token, gives me the 401 when previously didnt

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";
    });

Solution

  • Why the same token works fine for the ClientApp while invoking the API doesn't?

    Two things:

    1. The expiration time of the access token is unrelated to your actions.

    Once issued a JWT token can't be changed. By default the token expires after 3600 seconds.

    1. The difference between the application and the api: the application uses cookies, the api a bearer token.

    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.