How to apply custom validation to JWT token on each request for ASP.NET WebApi?
Solution 1
To add additional logic to authenticate or validate incoming tokens:
1) Using an Authentication Provider
Write a custom provider inherit from
OAuthBearerAuthenticationProvider
or implementIOAuthBearerAuthenticationProvider
in your custom authentication provider, override/implement
ValidateIdentity(...)
and/orRequestToken(...)
to check the incoming token with each requestUse your custom provider by assigning it to the
JwtBearerAuthenticationOptions.Provider
property
Example:
app.UseJwtBearerAuthentication(new JwtBearerAuthenticationOptions
{
// ... other properties here
Provider = new MyCustomTokenAuthenticationProvider()
// ... other properties here
});
2) Using A Token Handler
Write a custom token handler inherit from
JwtSecurityTokenHandler
override any relevant method you like to extend (there are many!)
Use your custom token handler by assigning it to the
JwtBearerAuthenticationOptions.TokenHandler
property
Example:
app.UseJwtBearerAuthentication(new JwtBearerAuthenticationOptions
{
// ... other properties here
TokenHandler = new MyCustomTokenHandler()
// ... other properties here
});
Solution 2
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.
Solution 3
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();
}
Related videos on Youtube
Natan
Updated on July 09, 2022Comments
-
Natan almost 2 years
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?
-
Geniuslead over 5 yearsHi Natan, how did you set your tokens to never expire? I was using linux expiry date which has limitations after JAN 2038
-
-
gorillapower over 7 yearsawesome answer thanks! Seems the documentation for this is lacking, using method 2), how would you add/modify Claims?
-
gorillapower over 7 yearsConversely, how would you handle token validation for method 1?
-
Carrie Kendall almost 7 yearsI'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 ownJwtBearerEvents
. 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. -
D.B almost 7 years@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.
-
Carrie Kendall almost 7 years@D.B I did. I will try to add an answer tomorrow
-
Amir Chatrbahr almost 7 yearsHey @Bishoy, I implemented the second approach and get SecurityTokenException on ValidateToken for expired tokens as expected but just don't know how to reject the request in that case?
-
mohit bansal almost 6 yearsSame issue as that of Amir. Request is not rejected with 401 but reaches the controller and invokes the action. If ValidateToken fails, I expect Unathorizedresponse be raised.
-
granadaCoder over 5 yearsFUTURE READER WARNING : 'JwtBearerAppBuilderExtensions.UseJwtBearerAuthentication(IApplicationBuilder, JwtBearerOptions)' is obsolete: 'See go.microsoft.com/fwlink/?linkid=845470' github.com/aspnet/AspNetCore/issues/2007
-
kenswdev over 2 yearsThis 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;