ASP.NET Core supports several authentication methods which are Basic, Bearer, Digest, OAuth and others. This article will show you how to build a Bearer authentication to your Web API using IAsyncAuthorizationFilter and IPolicyEvaluator interfaces.
Prerequisites
- Install .NET 5.0 preview version – https://dotnet.microsoft.com/download/dotnet-core
- Update Visual Studio to latest version. – Version 16.7.0 Preview 1.0
Bearer Authentication
Bearer authentication is an HTTP authentication scheme also called token authentication that involves security tokens called bearer tokens. Bearer Token is set in the Authorization header of HTTP Request.
Why not use built in [Authorize]?
ASP.NET core official documentation does not talk about how to implement a custom Bearer Authentication. I have seen ton of samples explaining either [Authorize] or IDENTITY providers or OAUTH type authentications. However, this approach does not work on WEB API 2.0 apps which is written in .NET Full Framework.
NOTE: I’ve used IAuthenticationFilter interface to implement authentication in WEB API 2.0.
Creating ASP.NET 5.0 WEB API Project
Fire up your favorite IDE and create a brand new ASP.NET CORE Web API project template. The default template is pretty good to get started to implement Bearer token authentication method.
Project edit view
After successfully creating API project, click on edit project file and you should be able to see TargetFramework is netcoreapp5.0 and LangVersion is C# 9.0 which is in preview mode.
<PropertyGroup> <TargetFramework>netcoreapp5.0</TargetFramework> <LangVersion>Preview</LangVersion> </PropertyGroup>
IAsyncAuthorizationFilter & IPolicyEvaluator
IAsyncAuthorizationFilter Interface – A filter that asynchronously confirms request authorization. Read more
IPolicyEvaluator Interface – Base class for authorization handlers that need to be called for a specific requirement type. Read more
Let’s implement IPolicyEvaluator interface first. The interface has two methods called AuthenticateAsync and AuthorizeAsync,
1) AuthenticateAsync method checks for Authorization header and read Bearer token from the request header.
- Check Authorization header present in the request.
- Read Bearer token and compare against the stored token.
- Once token match successfully, set some Claims thus, you want to identity the request later.
2) AuthorizeAsync method does check whether the request has been already evaluated by IPolicyEvaluator and looks Succeeded or Challenged status and return Policy Authorization Result.
Below, you can find complete code for PolicyEvaluator class.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public sealed class BearerPolicyEvaluator : IPolicyEvaluator | |
{ | |
private const string Scheme = "Bearer"; | |
public Task<AuthenticateResult> AuthenticateAsync(AuthorizationPolicy _, HttpContext context) | |
{ | |
if (!context.Request.Headers.ContainsKey("Authorization")) | |
return Task.FromResult(AuthenticateResult.Fail("No Authorization header found!")); | |
string authHeader = context.Request.Headers["Authorization"]; | |
string bearerToken = authHeader?.Replace("Bearer ", string.Empty); | |
if (!string.Equals(bearerToken, "authToken", StringComparison.Ordinal)) | |
{ | |
return Task.FromResult(AuthenticateResult.Fail("Invalid token")); | |
} | |
var claims = new[] | |
{ | |
new Claim(ClaimTypes.NameIdentifier, "1000"), | |
new Claim(ClaimTypes.Name, "Deepu Madhusoodanan") | |
}; | |
var identity = new ClaimsIdentity(claims, Scheme); | |
var principal = new ClaimsPrincipal(identity); | |
var ticket = new AuthenticationTicket(principal, Scheme); | |
var authenticateResult = AuthenticateResult.Success(ticket); | |
return Task.FromResult(authenticateResult); | |
} | |
public Task<PolicyAuthorizationResult> AuthorizeAsync(AuthorizationPolicy _, | |
AuthenticateResult authenticationResult, HttpContext context, | |
object resource) | |
{ | |
var authorizeResult = authenticationResult.Succeeded | |
? PolicyAuthorizationResult.Success() | |
: PolicyAuthorizationResult.Challenge(); | |
return Task.FromResult(authorizeResult); | |
} | |
} |
Next, implement IAsyncAuthorizationFilter interface.
OnAuthorizationAsync method calls above PolicyEvaluator API to get authentication and authorization result.
Configure services
Final step would be registering authentication interface in Startup.cs class
public void ConfigureServices(IServiceCollection services) { services.AddControllers(o => o.Filters.Add(new BearerAuthorizeFilter())); }
NOTE: Using this approach, you wouldn’t need to use any middleware like use.Authentication() or [Authorize] attribute on API controllers.
Source repository
Github – https://github.com/deepumi/aspnet-5-bearer-authentication/
Summary
In this post I described how to implement custom Bearer token in ASP.NET Core projects with out using built in Authorize mechanism.
A big thank you to Microsoft MVP Steve Gordon who recommended to use JWT tokens and built in [Authorize] mechanism for APS.NET core projects!
Hope you enjoy reading the article and please feel free to give this a try and let me know your thoughts and suggestions.