# Authorization - Hot Chocolate

> Protect fields and types in Hot Chocolate with the @authorize directive, integrating ASP.NET Core roles and policies for fine-grained access control.

Canonical source: https://chillicream.com/docs/hotchocolate/security/authorization

Authorization controls what an authenticated user can access. Hot Chocolate provides the `@authorize` directive for field-level and type-level access control, integrating with ASP.NET Core roles and policies.

Authentication is a prerequisite. You must first validate a user's identity before evaluating their permissions.

[Learn how to set up authentication](https://chillicream.com/docs/hotchocolate/security/authentication)

## Setup

After configuring authentication, complete these steps to enable authorization.

### 1\. Install the Authorization Package

Bash

```
dotnet add package HotChocolate.AspNetCore.Authorization
```

Warning

All `HotChocolate.*` packages need to have the same version.

### 2\. Register the Required Services

Call `AddAuthorization()` on both `IServiceCollection` (for ASP.NET Core services) and `IRequestExecutorBuilder` (for the `@authorize` directive and middleware):

C#

```
builder.Services.AddAuthorization();

builder
    .AddGraphQL()
    .AddAuthorization()
    .AddQueryType<Query>();
```

### 3\. Add Authorization Middleware

C#

```
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();

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

## Applying Authorization

The `@authorize` directive can be applied to types and fields. When applied to a type, it applies to every field on that type. A directive on a specific field overrides the one on the type.

Warning

**Use `HotChocolate.Authorization.AuthorizeAttribute`**, not `Microsoft.AspNetCore.Authorization.AuthorizeAttribute`. The Microsoft attribute does not integrate with the Hot Chocolate authorization pipeline. Using the wrong attribute is a common source of authorization not working.

C#

```
[Authorize]
public class User
{
    public string Name { get; set; }

    [Authorize(Roles = ["Administrator"])]
    public Address Address { get; set; }
}
```

With the source generator, you can apply `[Authorize]` to resolver methods:

C#

```
[QueryType]
public static partial class UserQueries
{
    [Authorize]
    public static async Task<User?> GetMeAsync(
        ClaimsPrincipal claimsPrincipal,
        UserService users,
        CancellationToken ct)
    {
        var userId = claimsPrincipal.FindFirstValue(ClaimTypes.NameIdentifier);
        return userId is not null ? await users.GetByIdAsync(userId, ct) : null;
    }
}
```

If no arguments are specified on `[Authorize]`, the directive requires the user to be authenticated. Unauthenticated users who access an authorized field receive a GraphQL error with the code `AUTH_NOT_AUTHENTICATED`, and the field value is set to `null`.

JSON

```
{
  "errors": [
    {
      "message": "The current user is not authorized to access this resource.",
      "path": ["me"],
      "extensions": {
        "code": "AUTH_NOT_AUTHENTICATED"
      }
    }
  ],
  "data": {
    "me": null
  }
}
```

## Roles

Roles provide a straightforward way to group users by access level. Add role claims to the `ClaimsPrincipal`:

C#

```
claims.Add(new Claim(ClaimTypes.Role, "Administrator"));
```

Then restrict access by role:

C#

```
[Authorize(Roles = ["Guest", "Administrator"])]
public class User
{
    public string Name { get; set; }

    [Authorize(Roles = ["Administrator"])]
    public Address Address { get; set; }
}
```

When multiple roles are specified, a user needs to match only one of them to gain access.

[Learn more about role-based authorization in ASP.NET Core](https://docs.microsoft.com/aspnet/core/security/authorization/roles)

## Policies

Policies decouple authorization logic from your GraphQL resolvers. A policy consists of an `IAuthorizationRequirement` and an `AuthorizationHandler<T>`.

Register policies on the service collection:

C#

```
builder.Services.AddAuthorization(options =>
{
    options.AddPolicy("AtLeast21", policy =>
        policy.Requirements.Add(new MinimumAgeRequirement(21)));

    options.AddPolicy("HasCountry", policy =>
        policy.RequireAssertion(context =>
            context.User.HasClaim(c => c.Type == ClaimTypes.Country)));
});

builder.Services.AddSingleton<IAuthorizationHandler, MinimumAgeHandler>();
```

Apply policies to fields:

C#

```
[Authorize(Policy = "AllEmployees")]
public class User
{
    public string Name { get; set; }

    [Authorize(Policy = "SalesDepartment")]
    public Address Address { get; set; }
}
```

The `@authorize` directive is repeatable. When multiple policies are specified, the user must satisfy all of them:

C#

```
[Authorize(Policy = "AtLeast21")]
[Authorize(Policy = "HasCountry")]
public class User
{
    public string Name { get; set; }
}
```

[Learn more about policy-based authorization in ASP.NET Core](https://docs.microsoft.com/aspnet/core/security/authorization/policies)

### Accessing IResolverContext in an AuthorizationHandler

When you need access to GraphQL-specific data in your authorization handler, use `IResolverContext` as the resource type:

C#

```
public class MinimumAgeHandler
    : AuthorizationHandler<MinimumAgeRequirement, IResolverContext>
{
    protected override Task HandleRequirementAsync(
        AuthorizationHandlerContext context,
        MinimumAgeRequirement requirement,
        IResolverContext resolverContext)
    {
        // Access GraphQL context data, arguments, etc.
        // Omitted for brevity
    }
}
```

## Allow Anonymous Access

Use `[AllowAnonymous]` to bypass authorization on specific fields. This is useful for registration or public content endpoints.

Warning

**Use `HotChocolate.Authorization.AllowAnonymousAttribute`**, not `Microsoft.AspNetCore.Authorization.AllowAnonymousAttribute`.

C#

```
[MutationType]
public static partial class AccountMutations
{
    [Authorize]
    public static async Task<User> AddAddressAsync(/* ... */)
    {
        // Requires authentication
    }

    [AllowAnonymous]
    public static async Task<User> RegisterAsync(/* ... */)
    {
        // Open to everyone
    }
}
```

`[AllowAnonymous]` removes all other authorization requirements on the field. Use it carefully to avoid exposing sensitive data.

## Global Authorization

Apply authorization to the entire GraphQL endpoint by calling `RequireAuthorization()`:

C#

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

This returns HTTP 401 for unauthorized requests and blocks access to all middleware including Nitro. To keep Nitro accessible while protecting the GraphQL endpoint, split the middleware:

C#

```
app.UseEndpoints(endpoints =>
{
    endpoints.MapGraphQLHttp().RequireAuthorization();
    endpoints.MapNitroApp();
});
```

[Learn more about available middleware](https://chillicream.com/docs/hotchocolate/server/endpoints)

## Next Steps

- **Need to set up authentication first?** See [Authentication](https://chillicream.com/docs/hotchocolate/security/authentication).
- **Need to protect against expensive queries?** See [Cost Analysis](https://chillicream.com/docs/hotchocolate/security/cost-analysis).
- **Need an overview of security options?** See [Security Overview](https://chillicream.com/docs/hotchocolate/security).
[Edit this page on GitHub](https://github.com/ChilliCream/graphql-platform/edit/main/website/content/docs/hotchocolate/security/authorization.md)

Maintained by ChilliCream. Last updated on **June 30, 2026** by **Tobias Tengler**
