Back to Graphql Platform

Authentication

website/src/docs/hotchocolate/v16/securing-your-api/authentication.md

16.1.0-p.1.105.1 KB
Original Source

Authentication determines a user's identity. It is a prerequisite for authorization and also lets you access the authenticated user in your resolvers, for example to build a me field that returns the current user's profile.

Hot Chocolate integrates with the ASP.NET Core authentication system, so you can reuse existing authentication configuration and any supported authentication provider.

Learn more about authentication in ASP.NET Core

Setup

Setting up authentication follows the same pattern as any ASP.NET Core application. The example below uses JWT bearer tokens, but you can substitute any authentication scheme that ASP.NET Core supports.

1. Install the JWT Bearer Package

<PackageInstallation packageName="Microsoft.AspNetCore.Authentication.JwtBearer" external />

2. Register the Authentication Scheme

csharp
// Program.cs
var signingKey = new SymmetricSecurityKey(
    Encoding.UTF8.GetBytes("MySuperSecretKey"));

builder.Services
    .AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
    .AddJwtBearer(options =>
    {
        options.TokenValidationParameters = new TokenValidationParameters
        {
            ValidIssuer = "https://auth.chillicream.com",
            ValidAudience = "https://graphql.chillicream.com",
            ValidateIssuerSigningKey = true,
            IssuerSigningKey = signingKey
        };
    });

This is an example configuration. Use a proper key management solution for production.

3. Add Authentication Middleware

Register the authentication middleware in the request pipeline:

csharp
// Program.cs
app.UseRouting();
app.UseAuthentication();

app.UseEndpoints(endpoints =>
{
    endpoints.MapGraphQL();
});

4. Install the Hot Chocolate Authorization Package

<PackageInstallation packageName="HotChocolate.AspNetCore.Authorization" />

5. Register Authorization on the Schema

csharp
// Program.cs
builder
    .AddGraphQL()
    .AddAuthorization()
    .AddQueryType<Query>();

Calling AddAuthorization() on the IRequestExecutorBuilder registers the @authorize directive and makes the authenticated user's identity available to resolvers. It does not lock out unauthenticated users. To restrict access, use authorization.

Accessing the ClaimsPrincipal

After authentication, the ClaimsPrincipal of the current user is available in your resolvers.

<ExampleTabs> <Implementation>
csharp
// Types/UserQueries.cs
[QueryType]
public static partial class UserQueries
{
    public static User? GetMe(ClaimsPrincipal claimsPrincipal, UserService users)
    {
        var userId = claimsPrincipal.FindFirstValue(ClaimTypes.NameIdentifier);

        if (userId is null)
        {
            return null;
        }

        return users.GetById(userId);
    }
}
</Implementation> <Code>
csharp
// Types/UserQueriesType.cs
public class UserQueriesType : ObjectType
{
    protected override void Configure(IObjectTypeDescriptor descriptor)
    {
        descriptor
            .Field("me")
            .Resolve(context =>
            {
                var claimsPrincipal = context.GetUser();
                var userId = claimsPrincipal?.FindFirstValue(ClaimTypes.NameIdentifier);

                if (userId is null)
                {
                    return null;
                }

                var users = context.Service<UserService>();
                return users.GetById(userId);
            });
    }
}
</Code> </ExampleTabs>

Use ClaimsPrincipal to read claims such as the user ID, email, or roles:

csharp
var userId = claimsPrincipal.FindFirstValue(ClaimTypes.NameIdentifier);
var email = claimsPrincipal.FindFirstValue(ClaimTypes.Email);
var isAdmin = claimsPrincipal.IsInRole("Administrator");

Modifying the ClaimsPrincipal

If you need to add claims or identities to the ClaimsPrincipal before it reaches your resolvers, register an IHttpRequestInterceptor:

csharp
// Interceptors/HttpRequestInterceptor.cs
public class HttpRequestInterceptor : DefaultHttpRequestInterceptor
{
    public override ValueTask OnCreateAsync(
        HttpContext context,
        IRequestExecutor requestExecutor,
        OperationRequestBuilder requestBuilder,
        CancellationToken cancellationToken)
    {
        var identity = new ClaimsIdentity();
        identity.AddClaim(new Claim(ClaimTypes.Country, "us"));
        context.User.AddIdentity(identity);

        return base.OnCreateAsync(context, requestExecutor, requestBuilder, cancellationToken);
    }
}
csharp
// Program.cs
builder
    .AddGraphQL()
    .AddHttpRequestInterceptor<HttpRequestInterceptor>();

Learn more about interceptors

Next Steps