Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Cannot validate token in UseJwtBearerAuthentication. Authorization has been denied

Using a single asp.net(4.6.1) web project, apparently I'm unable to validate the jwt token that was generated on the same server.
Startup.cs:

        var secret = Encoding.UTF8.GetBytes("12341234123412341234");
        var jwtFormatter = new CustomJwtFormat("Any", "local", secret);

        // This part checks the tokens
        app.UseJwtBearerAuthentication(new JwtBearerAuthenticationOptions
        {
            AuthenticationType = DefaultAuthenticationTypes.ExternalBearer,
            AuthenticationMode = AuthenticationMode.Active, // Block requests
            AllowedAudiences = new []{"Any"},
            TokenValidationParameters = new TokenValidationParameters
            {
                IssuerSigningKey = new InMemorySymmetricSecurityKey(secret),
                ValidAudience = "Any",
                ValidIssuer = "local"
            }
        });
        
        // This part issues tokens
        app.UseOAuthAuthorizationServer(new OAuthAuthorizationServerOptions
        {
            AllowInsecureHttp = false,
            TokenEndpointPath = new PathString("/auth"),
            AccessTokenExpireTimeSpan = TimeSpan.FromMinutes(30),
            Provider = new CustomOAuthProvider(),
            AccessTokenFormat = jwtFormatter,
            RefreshTokenFormat = jwtFormatter
            
        });

        app.UseWebApi(config);

The class that generates the tokens looks like

public class CustomJwtFormat : ISecureDataFormat<AuthenticationTicket>
{
    private readonly string _allowedAudience;
    private readonly string _issuer;
    private readonly byte[] _jwtTokenSignKey;

    public CustomJwtFormat(string allowedAudience, string issuer, byte[] jwtTokenSignKey)
    {
        _allowedAudience = allowedAudience;
        _issuer = issuer;
        _jwtTokenSignKey = jwtTokenSignKey;
    }

    public string Protect(AuthenticationTicket data)
    {
        if (data == null) throw new ArgumentNullException(nameof(data));
        
        var signingCredentials = new SigningCredentials
        (
            new InMemorySymmetricSecurityKey(_jwtTokenSignKey),
            "http://www.w3.org/2001/04/xmldsig-more#hmac-sha256",
            "http://www.w3.org/2001/04/xmlenc#sha256"
        );

        return new JwtSecurityTokenHandler().WriteToken(new JwtSecurityToken(
            _issuer, 
            _allowedAudience, 
            data.Identity.Claims, 
            DateTime.UtcNow, DateTime.UtcNow.AddMinutes(10), 
            signingCredentials
        ));
        
    }

    public AuthenticationTicket Unprotect(string protectedText)
    {
        throw new NotImplementedException();
    }
}

The tokens I receive from /auth look valid and pass the debugger on jwt.io (without marking base64 for signature) image

However UseJwtBearerAuthentication refuses to validate the token. image

What could be the possible reason for this ?

Moreover, I've tried manually validating the same token in a controller without [Authorize] and it would perfectly validate:

        var t = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpZCI6IjEiLCJpc3MiOiJsb2NhbCIsImF1ZCI6IkFueSIsImV4cCI6MTQ3MjkxMDcwMSwibmJmIjoxNDcyOTEwMTAxfQ.ipSrRSGmje7wfzERsd-M1IDFJnN99AIC4Hs7YX4FIeI";
        var TokenHandler = new JwtSecurityTokenHandler();;
        var key = Encoding.UTF8.GetBytes("12341234123412341234");
        SecurityToken validatedToken;
        TokenValidationParameters paras = new TokenValidationParameters()
        {
            IssuerSigningKey = new InMemorySymmetricSecurityKey(key),
            ValidAudience = "Any",
            ValidIssuer = "local"
        };
        TokenHandler.ValidateToken(t, paras, out validatedToken);

Owin 3.0.1.0 System.IdentityModel.Tokens.Jwt 4.0.3.308261200

like image 663
Alex Avatar asked Sep 03 '16 13:09

Alex


1 Answers

The problem wasn't in the token validation, but rather the that the claims were not passed on to Thread.CurrentPrincipal that the [Authorize] attribute was reading from.

In webapi config:

config.SuppressDefaultHostAuthentication();
config.Filters.Add(new HostAuthenticationFilter(DefaultAuthenticationTypes.ExternalBearer));

In startup config:

app.UseOAuthAuthorizationServer(new OAuthAuthorizationServerOptions
{
    AuthenticationType = DefaultAuthenticationTypes.ExternalBearer,
    ...
});

app.UseJwtBearerAuthentication1(new JwtBearerAuthenticationOptions()
{
    AuthenticationType = DefaultAuthenticationTypes.ExternalBearer,
    ..
});

In GrantResourceOwnerCredentials of the OAuthAuthorizationServerProvider:
use the same authentication type, which you can read from context.Options

var identity = new ClaimsIdentity(youClaimsList, context.Options.AuthenticationType);
context.Validated(identity);

And ensure all four places have the same string as AuthenticationType. If the HostAuthenticationFilter will have a different authenticationType as input, it will not pass on the claims from owin to webapi.

like image 151
Alex Avatar answered Nov 13 '22 18:11

Alex