I have a Web API that as already JwtBearer
schema validation in place. Now I need to add ApiKey
schema validation to the Web API to be used by a service.
I follow this guide, create the ApiKeyAttribute
class and decorated the controller method with [ApiKey]
attribute.
Still, when I call the Web API method, I get the 401 error.
Here is how the call is made:
//add "Authentication: Bearer somekey" header to every http call
httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("ApiKey", "somekey");
The method OnActionExecutionAsync
of ApiKeyAttribute
class is never called.
I try to add the Authentication schema like this to the Web API startup with no success at all:
builder.Services
.AddControllers().Services
.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
...
.AddAuthentication("ApiKey").Services //the second schema, ApiKey
.Add...
Instead, it returns
No authenticationScheme was specified, and there was no DefaultChallengeScheme found. The default schemes can be set using either AddAuthentication(string defaultScheme) or AddAuthentication(Action configureOptions).
Any clues?
Update 25-04-2002
For the sake of completeness, i add here the code of all relevant parts. It works fine with Bearer
scheme before i try to add ApiKey
scheme at start.
The attribute class:
[AttributeUsage(validOn: AttributeTargets.Class | AttributeTargets.Method)]
public class ApiKeyAttribute : Attribute, IAsyncActionFilter
{
private const string APIKEYNAME = "ApiKey";
public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
{
Console.WriteLine("ApiKeyAttribute HIT !!!"); //not passing here
if (!context.HttpContext.Request.Headers.TryGetValue(APIKEYNAME, out var extractedApiKey))
{
context.Result = new ContentResult()
{
StatusCode = 401,
Content = "Api Key was not provided"
};
return;
}
var appSettings = context.HttpContext.RequestServices.GetRequiredService<IConfiguration>();
var apiKey = appSettings.GetValue<string>(APIKEYNAME);
if (!apiKey.Equals("TESTE"))
{
context.Result = new ContentResult()
{
StatusCode = 401,
Content = "Api Key is not valid"
};
return;
}
await next();
}
}
The controller with the decorated method with ApiKey
:
[ApiController]
[Route("[controller]")]
public class SomeController : ControllerBase
{
...
[HttpGet()]
[Produces("application/json")]
//[Authorize(Roles = Roles.Read)] removed temporarily so i can put ApiKey scheme before i enable again the Bearer scheme that allows Role authorization. It is desirable to enable both schemes on same methods.
[ApiKey]
public List<Rule> foo() {
...
}
}
Program:
var builder = WebApplication.CreateBuilder(args);
... //configs
builder.Services
.AddControllers().Services
.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
...
.AddAuthentication("ApiKey").Services //the second schema, ApiKey
.Add...
var app = builder.Build();
...
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.MapControllerRoute(
name: "default",
pattern: "{controller}/{action=Index}/{id?}");
app.MapFallbackToFile("index.html"); ;
app.Run();
Update 26-04-2026
Using the Attribute class don't seem to be the way to implement ApiKey schema validation, or at least i failed to put it to work.
I change the ApiKey
schema validation implementation to the one posted here. Works well as the only schema validation.
Still need to find out how to add it as the second validation schema.
CodePudding user response:
Set Authentication Scheme to the controller explicitly.
[ApiController]
[Route("[controller]")]
[Authorize(AuthenticationSchemes = "ApiKey")]
public class SomeController : ControllerBase
{
// ACTIONS
}
To set the second Authentication Scheme, You can use the below approach:
[ApiController]
[Route("[controller]")]
[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme "," apiKey.ApiKeyAuthenticationDefaults.AuthenticationScheme)]
public class SomeController : ControllerBase
{
// ACTIONS
}