Search code examples
c#asp.net-core.net-8.0

Unauthorized (http 401) error with .NET 8 custom token handler


In .NET 8, I'm trying to implement a custom JWT token handler. The incoming JWT is missing the aud and iss claims. This may be incompliant with the OAuth standard (not sure), but it's something I have to deal with. I've read about the breaking changes in .NET 8 concerning JWT token validation: https://github.com/aspnet/Announcements/issues/508. So I'm trying to implement a TokenHandler rather than a ISecurityTokenValidator.

When I send a request, I get an HTTP 401 (Unauthorized) error back. Currently, I hardcoded the result of TokenValidationResult to be as forgiving as possible.

Do I need to change the code in any way?

var builder = WebApplication.CreateBuilder(args);

builder.Services
.AddJwtBearer(options =>
    {
        options.TokenValidationParameters = new TokenValidationParameters
        {
            ValidateIssuer = false,
            ValidateAudience = false,
            ValidateLifetime = false,
            ValidateIssuerSigningKey = false,
            IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("foobar"))
        };

        options.TokenHandlers.Clear();
        options.TokenHandlers.Add(new MyJwtTokenHandler());

The JWT token handler:

public class MyJwtTokenHandler : TokenHandler
{
    public override Task<TokenValidationResult> ValidateTokenAsync(string token, TokenValidationParameters validationParameters)
    {
        ClaimsIdentity identity = new(
        [
            new(ClaimTypes.Name, "John Doe"),
            new(ClaimTypes.Email, "[email protected]")
        ]);

        var result = new TokenValidationResult
        {
            IsValid = true,
            ClaimsIdentity = identity
        };

        return Task.FromResult(result);
    }
}

Solution

  • In my test if without "SecurityToken", OnChallenge event will report a failure. enter image description here

    You could try following code works to implement from TokenHandler

        public class MyJwtTokenHandler : TokenHandler
        {
            public override  Task<TokenValidationResult> ValidateTokenAsync(string token, TokenValidationParameters validationParameters)
            {
    
                var claims = new List<Claim>
                    {
                        new(ClaimTypes.Name, "John Doe"),
                        new(ClaimTypes.Email, "[email protected]")
                };
    
                var key = new SymmetricSecurityKey(Encoding.ASCII.GetBytes("xxx"));
    
                var tokenDescriptor = new SecurityTokenDescriptor
                {
                    Subject = new ClaimsIdentity(claims),           
                    Expires = DateTime.UtcNow.Add(TimeSpan.FromMinutes(4)),
                    SigningCredentials = new SigningCredentials(key, SecurityAlgorithms.HmacSha256),
                };
    
                var tokenHandler = new JwtSecurityTokenHandler();
                var securityToken = tokenHandler.CreateToken(tokenDescriptor);
    
                var result = new TokenValidationResult
                {
                    IsValid = true,
                    SecurityToken = securityToken,
                    ClaimsIdentity = new ClaimsIdentity(claims,"jwt"),            
    
                };
                return Task.FromResult(result);
            }
        }