In an ASP.NET Core API project, I need to validate another JWT Bearer token located in header different than the Authorization header. For example, imagine sending a GET request to get products to /api/products
with a Bearer token in a header named AccessToken
.
curl --location --request GET 'https://localhost/api/products' \
--header 'AccessToken: <bearer_token>'
I'm referencing the Microsoft.AspNetCore.Authentication.JwtBearer package and setting authentication in the API project like this:
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(JwtBearerDefaults.AuthenticationScheme, options => Configuration.Bind("JwtSettings", options));
However, I cannot find anything regarding a header name inside the JwtBearerOptions Class.
How can I configure the JWT authentication to read the JWT from a header named "AccessToken"? Is it even possible using the Microsoft.AspNetCore.Authentication.JwtBearer package?
The solutions seems to be to use the JwtBearerEvents class. In it, there's a delegate property named OnMessageReceived that it's "invoked when a protocol message is first received". The delegate will pass a object of type of MessageReceivedContext, where it has a property named Token that according to the documentation "This will give the application an opportunity to retrieve a token from an alternative location".
Create a class that inherits from JwtBearerEvents and in the OnMessageReceived event set the token in the context object to the value from the header "AccessToken".
/// <summary>
/// Singleton class handler of events related to JWT authentication
/// </summary>
public class AuthEventsHandler : JwtBearerEvents
{
private const string BearerPrefix = "Bearer ";
private AuthEventsHandler() => OnMessageReceived = MessageReceivedHandler;
/// <summary>
/// Gets single available instance of <see cref="AuthEventsHandler"/>
/// </summary>
public static AuthEventsHandler Instance { get; } = new AuthEventsHandler();
private Task MessageReceivedHandler(MessageReceivedContext context)
{
if (context.Request.Headers.TryGetValue("AccessToken", out StringValues headerValue))
{
string token = headerValue;
if (!string.IsNullOrEmpty(token) && token.StartsWith(BearerPrefix))
{
token = token.Substring(BearerPrefix.Length);
}
context.Token = token;
}
return Task.CompletedTask;
}
}
Finally, add the events class to the JWT authentication at the Startup class.
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(JwtBearerDefaults.AuthenticationScheme, options =>
{
Configuration.Bind("JwtSettings", options);
options.Events = AuthEventsHandler.Instance;
});