.netasp.net-coreidentitybearer-token

.Net Identity Bearer Multiple Expiration Times


I'm developing .Net WebApi with Identity project and I'm using Bearer Authentication. I have two types of clients. Mobile and Web projects. They need to have different token expiration times. I have different API's for mobile and web login.

Bearer Auth Configuration:

builder.Services
       .AddOptions<BearerTokenOptions>(IdentityConstants.BearerScheme)
       .Configure(options =>
                  {
                      options.BearerTokenExpiration = TimeSpan.FromHours(24);
                  });

For example mobile app token should expiry in 14 days, web expiration 1 day. But I can only give one scheme options.

I tried to change bearer token options in controller but nothing changed:

_bearerTokenOptions.CurrentValue.BearerTokenExpiration = TimeSpan.FromHours(1);

Solution

  • You can achieve this by creating two different JwtBearer authentication schemes, each with its own token expiration time.Then you can customize the token lifetime based on the client type (mobile or web).

    For Example:

    Configure the jwt authentication in Program.cs

    builder.Services.AddAuthentication(options =>
    {
        options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
        options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
    })
    .AddJwtBearer("WebScheme", options =>
    {
        options.TokenValidationParameters = new TokenValidationParameters
        {
            // Your token validation parameters
        };
        options.Events = new JwtBearerEvents
        {
            OnTokenValidated = context =>
            {
                // Additional logic when token is validated
                return Task.CompletedTask;
            }
        };
        options.SaveToken = true;
    })
    .AddJwtBearer("MobileScheme", options =>
    {
        options.TokenValidationParameters = new TokenValidationParameters
        {
            // Your token validation parameters
        };
        options.Events = new JwtBearerEvents
        {
            OnTokenValidated = context =>
            {
                // Additional logic when token is validated
                return Task.CompletedTask;
            }
        };
        options.SaveToken = true;
    });
    

    Then configure the generate token method with changed time

    private string GenerateJwtToken(int expirationInDays)
    {
        var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_configuration["Jwt:Key"]));
        var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);
    
        var claims = new[]
        {
            new Claim(JwtRegisteredClaimNames.Sub, "user_id"),
            //...
        };
    
        var token = new JwtSecurityToken(
            _configuration["Jwt:Issuer"],
            _configuration["Jwt:Audience"],
            claims,
            expires: DateTime.Now.AddDays(expirationInDays),    //difference here
            signingCredentials: creds);
    
        return new JwtSecurityTokenHandler().WriteToken(token);
    }
    

    Call this method for different client

    [HttpPost("login-web")]
    public IActionResult LoginWeb([FromBody] LoginModel model)
    {
        // Perform your user authentication here
    
        var token = GenerateJwtToken(1); // 1 day for web
        return Ok(new { Token = token });
    }
    
    [HttpPost("login-mobile")]
    public IActionResult LoginMobile([FromBody] LoginModel model)
    {
        // Perform your user authentication here
    
        var token = GenerateJwtToken(14); // 14 days for mobile
        return Ok(new { Token = token });
    }
    

    You may also try to store the jwt tokens which contains the client identifier like deviceid or ip in database.