Could use a hand getting JwtBearer or OpenIdConnect working with a webapi.
Generally when configuring an app I look for OpenIdConnect settings and configure as expected. This works and I've got single signon working with several apps. I believe this should eliminate keycloak as a suspect variable.
With the code below I was getting a 302 and after much searching added in the options.Events
which led to the current 401 error:
< HTTP/2 401
< date: Sun, 26 Feb 2023 16:29:54 GMT
< content-length: 0
< www-authenticate: Bearer error="invalid_token"
< strict-transport-security: max-age=15724800; includeSubDomains
However, I can take the bearer token being used and copy it out to jwt.io and it shows as valid. Not sure why the webapi is struggling here.
When I test, I'm using the swagger, clicking on the authentication and copying in 'Bearer ' then Executing a method which has the '[Authorize]'.
After increasing log level I'm now also seeing:
info: Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerHandler[7]
Bearer was not authenticated. Failure message: No SecurityTokenValidator available for token.
info: Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerHandler[12]
AuthenticationScheme: Bearer was challenged.
I've updated packages. Here's the code snippet:
Startup.cs
services.AddAuthentication(options =>
{
options.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddJwtBearer(options =>
{
options.MetadataAddress = Configuration.GetSection("appSettings")["auth0Domain"] + "/.well-known/openid-configuration";
options.Audience = Configuration.GetSection("appSettings")["auth0Audience"];
options.RequireHttpsMetadata = false;
options.IncludeErrorDetails = true;
options.TokenValidationParameters = new Microsoft.IdentityModel.Tokens.TokenValidationParameters
{
ValidateIssuer = false,
ValidateAudience = false
};
//add more configs
options.Events = new JwtBearerEvents
{
OnMessageReceived = context =>
{
context.Token = context.Request.Headers["Authorization"];
return Task.CompletedTask;
},
};
});
IdentityModelEventSource.ShowPII = true;
// Configure Cors
services.AddCors(options =>
{
options.AddDefaultPolicy(
builder =>
{
builder.WithOrigins()
.AllowAnyOrigin()
.AllowAnyMethod()
.AllowAnyHeader();
//builder.WithOrigins("http://example.com",
// "http://www.contoso.com");
});
});
public void Configure(IApplicationBuilder app, IWebHostEnvironment env, Service service)
{
Globals.service = service;
service.Start();
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
// Enable middleware to serve generated Swagger as a JSON endpoint.
app.UseSwagger();
// Enable middleware to serve swagger-ui (HTML, JS, CSS, etc.),
// specifying the Swagger JSON endpoint.
app.UseSwaggerUI(c =>
{
c.SwaggerEndpoint("/swagger/v1/swagger.json", "My API V1");
});
//app.UseHttpsRedirection();
app.UseRouting();
// Allow cross-site calls
app.UseCors();
app.UseAuthentication();
app.UseAuthorization();
//app.UseMiddleware<ApiKeyMiddleware>();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
app.UseWebSockets();
// Handle incoming webrequests in order to start WebSockets
app.Use(async (context, next) => { await Globals.service.tm.HandleWebRequest(context, next); });
}
You should not need to add the options.Events part, if you pass the token via the usual Authorization: bearer header.
I recently blogged about troubleshooting JwtBearer problems here and I hope that can give you some ideas. See my comments for additional things to add to your question.