Configure Kestrel GraphQL to authenticate user

26 views Asked by At

I am creating and configuring a GraphQL server, and a Playground.

The endpoint /graphql is already requiring authentication, but the /playground is complaining it can't access schema (access denied). Right after opening the playground, GraphQL show "error": "Response not successful: Received status code 401" (not authorized).

Indeed, if I try to access /graphql directly, it also gives me access denied. It seems it is not requiring the browser to authenticate the user.

I'd like to configure /playground to authenticate the user, and use the token to call /graphql.

This is the WebApplication build:

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddHealthChecks();

Settings.AppSettings = builder.Configuration;

builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme).AddMicrosoftIdentityWebApi(builder.Configuration.GetRequiredSection("AzureAd"));

builder.Services.AddSingleton<AnyScalarGraphType>();
builder.Services.AddSingleton<ServiceGraphType>();

builder.Services.AddTransient<Query>();
builder.Services.AddTransient<Mutation>();

builder.Services.AddTransient<ISchema>(s => DocumentSchema.CreateSchema());

builder.Services.AddGraphQL(b => b
  .AddErrorInfoProvider(opt => opt.ExposeExceptionDetails = true)
  .AddUserContextBuilder(new Func<HttpContext, Dictionary<string, object?>>(httpContext => new RuntimeContext(httpContext)))
  .AddSystemTextJson()
);

builder.Services.AddControllers()
    .AddJsonOptions(options =>
    {
      options.JsonSerializerOptions.Converters.Add(new DateOnlyJsonConverter());
    });

var app = builder.Build();

app.UseAuthentication();
app.UseAuthorization();

app.MapHealthChecks("/health");

app.UseGraphQL("/graphql", config =>
{
  config.AuthorizationRequired = true;
});

if (app.Environment.IsDevelopment())
{
  app.UseDeveloperExceptionPage();
  app.UseGraphQLPlayground(
    "/playground",
    new GraphQL.Server.Ui.Playground.PlaygroundOptions
    {
      GraphQLEndPoint = "/graphql",
      RequestCredentials = GraphQL.Server.Ui.Playground.RequestCredentials.Include
    }
  );
}

await app.RunAsync();

This is the appsettings.json:

{
  "Logging": {
    "LogLevel": {
      "Default": "Warning",
      "Microsoft.AspNetCore": "Warning"
    }
  },
  "AllowedHosts": "*",
  "Kestrel": {
    "Endpoints": {
      "Https": {
        "Url": "https://+:4002"
      }
    }
  }
}
1

There are 1 answers

1
Md Farid Uddin Kiron On

The endpoint /graphql is already requiring authentication, but the /playground is complaining it can't access schema (access denied). Right after opening the playground, GraphQL show "error": "Response not successful: Received status code 401" (not authorized).

Well, based on your scenario and description, the issue lies in how Playground interacts with your GraphQL endpoint. Playground itself doesn't handle authentication by default, even though your /graphql endpoint requires authorization.

While I investigating your shared code, I noticed, in your code, you've set RequestCredentials to Include for Playground options. This instructs Playground to include any existing browser credentials in the request.

However, for this to work, your application needs to have a mechanism to set those credentials before accessing Playground. This typically involves implementing a login flow where the user obtains an access token and stores it in the browser.

Thus, upon successful login, generate an access token (using JWT or similar) and store it securely in the browser and then you could use that.

You could try following modification:

app.UseWhen(context => context.Request.Path.StartsWithSegments("/playground"), appBuilder =>
    {
        appBuilder.UseAuthentication();
    });

    app.UseGraphQLPlayground(
        "/playground",
        new GraphQL.Server.Ui.Playground.PlaygroundOptions
        {
            GraphQLEndPoint = "/graphql",
            RequestCredentials = GraphQL.Server.Ui.Playground.RequestCredentials.Include
        }
    );

Note: Please refer to this official document, could be resourceful for you.