Authorization fails on multiple authentication schemes unless RequireAuthorization() is set
JWT (the second specified auth method) will fail with this setup, even if ASP.NET appears to recognize the token.
Authentication does appear to pass, as it will return a null result, but the user claims are empty.
services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
.AddCookie(option => { })
.AddJwtBearer(options =>
options.TokenValidationParameters =
new TokenValidationParameters();
services.AddAuthorization(options =>
var defaultAuthorizationPolicyBuilder = new AuthorizationPolicyBuilder(CookieAuthenticationDefaults.AuthenticationScheme, JwtBearerDefaults.AuthenticationScheme);
defaultAuthorizationPolicyBuilder = defaultAuthorizationPolicyBuilder.RequireAuthenticatedUser();
options.DefaultPolicy = defaultAuthorizationPolicyBuilder.Build();
services
.AddGraphQLServer()
.AddAuthorization();
app.UseEndpoints(endpoints =>
endpoints.MapGraphQL()
// .RequireAuthorization(); // Uncommenting this causes it to work again, but locks down the entire schema
Relevant log output
"errors": [
"message": "The current user is not authorized to access this resource.",
"locations": [
"line": 3,
"column": 5
"path": [
"me",
"contact"
"extensions": {
"code": "AUTH_NOT_AUTHENTICATED"
"data": {
"me": {
"contact": null
Additional Context?
No response
Product
Hot Chocolate
Version
12.0.0-rc.12
I took another look at it and found a workable solution. It is based on the HttpRequestInterceptor
, which you can read more about here. In the example below I implemented the default cookie authentication as well as a simple basic authentication I quickly implemented myself.
By adding a HTTP request interceptor I was able to authenticate the user through either cookie or basic authentication.
I registered a HttpRequestInterceptor
in ConfigureServices
:
services.AddHttpRequestInterceptor<HttpRequestInterceptor>()
which I then implemented as follows:
public class HttpRequestInterceptor : DefaultHttpRequestInterceptor
private IPolicyEvaluator _policyEvaluator;
public HttpRequestInterceptor(IPolicyEvaluator policyEvaluator)
_policyEvaluator = policyEvaluator;
public override async ValueTask OnCreateAsync(HttpContext context,
IRequestExecutor requestExecutor, IQueryRequestBuilder requestBuilder,
CancellationToken cancellationToken)
var defaultAuthorizationPolicyBuilder = new AuthorizationPolicyBuilder(CookieAuthenticationDefaults.AuthenticationScheme, "BasicAuthentication");
defaultAuthorizationPolicyBuilder = defaultAuthorizationPolicyBuilder.RequireAuthenticatedUser();
await _policyEvaluator.AuthenticateAsync(defaultAuthorizationPolicyBuilder.Build(), context);
await base.OnCreateAsync(context, requestExecutor, requestBuilder,
cancellationToken);
I took another look at it and found a workable solution. It is based on the HttpRequestInterceptor
, which you can read more about here. In the example below I implemented the default cookie authentication as well as a simple basic authentication I quickly implemented myself.
By adding a HTTP request interceptor I was able to authenticate the user through either cookie or basic authentication.
I registered a HttpRequestInterceptor
in ConfigureServices
:
services.AddHttpRequestInterceptor<HttpRequestInterceptor>()
which I then implemented as follows:
public class HttpRequestInterceptor : DefaultHttpRequestInterceptor
private IPolicyEvaluator _policyEvaluator;
public HttpRequestInterceptor(IPolicyEvaluator policyEvaluator)
_policyEvaluator = policyEvaluator;
public override async ValueTask OnCreateAsync(HttpContext context,
IRequestExecutor requestExecutor, IQueryRequestBuilder requestBuilder,
CancellationToken cancellationToken)
var defaultAuthorizationPolicyBuilder = new AuthorizationPolicyBuilder(CookieAuthenticationDefaults.AuthenticationScheme, "BasicAuthentication");
defaultAuthorizationPolicyBuilder = defaultAuthorizationPolicyBuilder.RequireAuthenticatedUser();
await _policyEvaluator.AuthenticateAsync(defaultAuthorizationPolicyBuilder.Build(), context);
await base.OnCreateAsync(context, requestExecutor, requestBuilder,
cancellationToken);
I tried the workaround but seems it's missing a DI for IPolicyEvaluator, have you got any written? and as per Hotchocolate documentation you have referred in the post it kind of says HttpInterceptor will be invoked after authentication, any suggestions please.
Great workaround @daanlenaerts !
To prevent the duplication of authorization policies, you can use the IAuthorizationPolicyProvider
:
public class HttpRequestInterceptor : DefaultHttpRequestInterceptor
private readonly IPolicyEvaluator _policyEvaluator;
private readonly IAuthorizationPolicyProvider _policyProvider;
public HttpRequestInterceptor(IPolicyEvaluator policyEvaluator,
IAuthorizationPolicyProvider policyProvider)
_policyEvaluator = policyEvaluator;
_policyProvider = policyProvider;
public override async ValueTask OnCreateAsync(HttpContext context,
IRequestExecutor requestExecutor, IQueryRequestBuilder requestBuilder,
CancellationToken cancellationToken)
await _policyEvaluator.AuthenticateAsync(await _policyProvider.GetDefaultPolicyAsync(), context);
await base.OnCreateAsync(context, requestExecutor, requestBuilder, cancellationToken);
I am having a similar issue, adding DefaultAuthenticateScheme cause a 401 furthermore the interceptor is not even working
services.AddAuthentication(opt =>
opt.DefaultAuthenticateScheme = IISDefaults.AuthenticationScheme;
opt.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
info: Microsoft.AspNetCore.Hosting.Diagnostics[1]
Request starting HTTP/1.1 GET https://localhost:44337/graphql/?query=query{%20employees%20{%20firstName%20}%20} - -
trce: Microsoft.AspNetCore.HostFiltering.HostFilteringMiddleware[2]
All hosts are allowed.
dbug: Microsoft.AspNetCore.StaticFiles.StaticFileMiddleware[3]
The request path does not match the path filter
dbug: Microsoft.AspNetCore.Routing.Matching.DfaMatcher[1001]
1 candidate(s) found for the request path '/graphql/'
dbug: Microsoft.AspNetCore.Routing.Matching.DfaMatcher[1005]
Endpoint 'Hot Chocolate GraphQL Pipeline' with route pattern '/graphql/{**slug}' is valid for the request path '/graphql/'
dbug: Microsoft.AspNetCore.Routing.EndpointRoutingMiddleware[1]
Request matched endpoint 'Hot Chocolate GraphQL Pipeline'
info: Microsoft.AspNetCore.Authorization.DefaultAuthorizationService[2]
Authorization failed. These requirements were not met:
Handler assertion should evaluate to true.
info: Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerHandler[2]
Successfully validated the token.
info: Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerHandler[12]
AuthenticationScheme: Bearer was challenged.
info: Microsoft.AspNetCore.Hosting.Diagnostics[2]
Request finished HTTP/1.1 GET https://localhost:44337/graphql/?query=query{%20employees%20{%20firstName%20}%20} - - - 401 - - 23.1461ms