17

Is it possible to add custom validation to each request when authenticating web api calls using a bearer token?

I'm using the following configuration and the application already validates the JWT tokens correctly.

app.UseOAuthAuthorizationServer(new OAuthAuthorizationServerOptions
{
    AuthenticationType = "jwt",
    TokenEndpointPath = new PathString("/api/token"),
    AccessTokenFormat = new CustomJwtFormat(),
    Provider = new CustomOAuthProvider(),
});

app.UseJwtBearerAuthentication(new JwtBearerAuthenticationOptions
{
    AllowedAudiences = new[] { "all" },
    IssuerSecurityTokenProviders = new[] { new SymmetricKeyIssuerSecurityTokenProvider(Config.JWT_Issuer, Config.JWT_Key) },,

});

Now, because tokens are set to never expire, I'd like to add an additional custom validation step to each request made with a bearer token, so I can validate some additional information per request and deny access if needed.

Where is the right place to add this validation for each request?

1
  • Hi Natan, how did you set your tokens to never expire? I was using linux expiry date which has limitations after JAN 2038 Commented Feb 18, 2019 at 16:12

3 Answers 3

27

To add additional logic to authenticate or validate incoming tokens, there are 2 methods.

1. Using a custom authentication provider


  1. Write a custom provider, inheriting from OAuthBearerAuthenticationProvider or implementing IOAuthBearerAuthenticationProvider

  2. In your custom authentication provider, override/implement ValidateIdentity(...) and/or RequestToken(...) depending on your aim, to check the incoming token with each request

ValidateIdentity as per source code:

Invoked before the System.Security.Claims.ClaimsIdentity is created. Gives the application an opportunity to find the identity from a different location, adjust, or reject the token.

RequestToken as per source code:

Called each time a request identity has been validated by the middleware. By implementing this method the application may alter or reject the identity which has arrived with the request.

  1. Use your custom provider, by setting the JwtBearerAuthenticationOptions.Provider property

Example:

app.UseJwtBearerAuthentication(new JwtBearerAuthenticationOptions
{
    // ... other properties here
    Provider = new MyCustomTokenAuthenticationProvider()
    // ... other properties here
});

2. Using a (custom) token handler

  1. Write a custom token handler, inheriting from JwtSecurityTokenHandler

  2. Override any relevant method you like to extend (there are many!)

  3. Use your custom token handler by setting the JwtBearerAuthenticationOptions.TokenHandler property

Example:

app.UseJwtBearerAuthentication(new JwtBearerAuthenticationOptions
{
    // ... other properties here
    TokenHandler = new MyCustomTokenHandler()
    // ... other properties here
});
Sign up to request clarification or add additional context in comments.

8 Comments

awesome answer thanks! Seems the documentation for this is lacking, using method 2), how would you add/modify Claims?
Conversely, how would you handle token validation for method 1?
I'm not sure about the first solution, but as for the second solution, this will no longer work due to changes in the JwtBearerOptions. It seems the best way is to implement your own JwtBearerEvents. I am going to try to implement a solution (using in-memory revocation post-validate) and post a solution if I can figure it out.
@CarrieKendall , any of the above solutions work with the new JwtBearerOption, did you figure out how to implement a custom validation with it. I would appreciate it if you can share your solution.
FUTURE READER WARNING : 'JwtBearerAppBuilderExtensions.UseJwtBearerAuthentication(IApplicationBuilder, JwtBearerOptions)' is obsolete: 'See go.microsoft.com/fwlink/?linkid=845470' github.com/aspnet/AspNetCore/issues/2007
|
15

on .Net Core you can add this to the JwtBearerOptions:

options.Events = new JwtBearerEvents
{
    OnTokenValidated = AdditionalValidation
};

Where your Validation function could look like this:

private static Task AdditionalValidation(TokenValidatedContext context)
{
    if ( /* any validation */ ) 
    {
        context.Fail("Failed additional validation");
    }

    return Task.CompletedTask;
}

The good news is that context will include all you need, the JWT Token, the HttpContext, the ClaimsPrincipal, etc.

1 Comment

This answer nailed it for me. Here are a couple statements I used to get at the claims (SID in this example) inside the AdditionalValidation method: if (context.SecurityToken is JwtSecurityToken accessToken) { if (context.Principal.Identity is ClaimsIdentity claims) { var sid = claims.FindFirst(ClaimTypes.Sid).Value;
1

The best way I would say is to write custom attribute. You need to inherit AuthorizeAttribute class and overridde AuthorizeCore method, there you can add custom validation.

Once you are done, just decorate your controller or method with it.

https://msdn.microsoft.com/en-us/library/system.web.mvc.authorizeattribute(v=vs.118).aspx

Implementation example:

public class MyCustomAttribute : AuthorizeAttribute
{
    protected override bool AuthorizeCore(HttpContextBase httpContext)
    {
        // your validation here
    }
}

Usage examle:

[MyCustom]
public ActionResult MyAction()
{
    return View();
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.