I'm trying to get JWT bearer authentication in an ASP.Net API gateway using Ocelot to work with multiple authorities/issuers. One issuer is Auth0 and the other is an in-house authentication server based on IdentityServer4; we are trying to migrate away from Auth0 but have external clients that still depend on it, so we would like to support both until everything is fully tested for them to switch.
According to this MSDN blog post, it should be possible to use multiple authorities by setting TokenValidationParameters.ValidIssuers
instead of JwtBearerOptions.Authority
. However, I have tested this with and without Ocelot and no authentication occurs if the Authority is not set to the authority who issued the token, no matter the contents of TokenValidationParameters.ValidIssuers
.
Does anybody know how to get this working? This is how I'm setting up authentication. It works only if the commented line is uncommented (and only for tokens issued by that single authority). I'm expecting Ocelot or ASP.Net Core to get the key from the issuing server; both provide JWKs by .well-known/openid-configuration which works with the ASP.Net Core middleware.
public static void AddJwtBearerAuthentication(this IServiceCollection services, IConfiguration configuration)
{
services
.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddJwtBearer(JwtBearerDefaults.AuthenticationScheme, options =>
{
//options.Authority = configuration["Jwt:Authority"];
options.Audience = configuration["Jwt:Audience"];
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = true,
ValidateIssuerSigningKey = true,
ValidateAudience = true,
ValidAudience = configuration["Jwt:Audience"],
ValidIssuers = configuration
.GetSection("Jwt:Authorities")
.AsEnumerable()
.Select(kv => kv.Value)
.Where(s => !string.IsNullOrEmpty(s))
.ToArray()
};
});
}
The output of Ocelot when a client who has the wrong issuer (or when we're using TokenValidationParameters.ValidIssuer
/ValidIssuers
) connects is:
[16:35:37 WRN] requestId: _____, previousRequestId: no previous request id, message: Error Code: UnauthenticatedError Message: Request for authenticated route _____ by was unauthenticated errors found in ResponderMiddleware. Setting error response for request path:_____, request method: POST
This is a client_credentials authentication hence the lack of a username after "by". As you can see Ocelot doesn't say what the exact problem is. The ASP.Net Core JWT bearer middleware (without Ocelot) just says the signature is invalid. I suspect it either isn't looking at the TokenValidationParameters
, or I've misunderstood the purpose of them.