ASP.NET Core 5.0 – Bearer Authentication


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

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.

Authorization: Bearer API Token

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.

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.

public sealed class BearerAuthorizeFilter : IAsyncAuthorizationFilter
{
public async Task OnAuthorizationAsync(AuthorizationFilterContext context)
{
if (context?.HttpContext?.Request?.Headers == null) throw new ArgumentNullException(nameof(context));
if (!context.HttpContext.Request.Headers.ContainsKey("Authorization"))
context.Result = CreateUnauthorized();
var policyEvaluator = context.HttpContext.RequestServices.GetRequiredService<IPolicyEvaluator>();
var authenticateResult = await policyEvaluator.AuthenticateAsync(default, context.HttpContext);
var authorizeResult = await policyEvaluator.AuthorizeAsync(default, authenticateResult, context.HttpContext, context);
if (authorizeResult.Challenged)
{
context.Result = CreateUnauthorized();
return;
}
context.HttpContext.User = authenticateResult.Principal;
static IActionResult CreateUnauthorized() => new UnauthorizedObjectResult(new ErrorMessage("Unauthorized", 401));
}
}

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.