> ## Documentation Index
> Fetch the complete documentation index at: https://docs.neuro-tech.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Authorization

> Protect routes with controller-level authorization middleware and method-level requirements

## Authentication comes first

Authorization requirements only make sense once the router knows which authentication schemes it should advertise.

```csharp theme={null}
ControllerEndpointRouter Router = new ControllerEndpointRouter(
    "/api",
    true,
    new CamelCaseParameterNameCodec());

Router.UseAuthenticationScheme(HttpAuthenticationSchemes.GetAccountsAuthenticationScheme());
Router.UseAuthenticationScheme(HttpAuthenticationSchemes.GetLegalSignatureScheme());
Router.UseAuthenticationScheme(HttpAuthenticationSchemes.GetAnonymousScheme());
```

Those schemes operate at the router level. Authorization then decides what an authenticated caller is allowed to do on a given endpoint.

## Two attributes, two jobs

Authorization is split into two parts:

* `[UseAuthorization]` — turns on authorization middleware for a controller
* `[Authorization]` — adds role or permission requirements to a specific method

## Attribute-based authorization

```csharp theme={null}
[Controller]
[Route("/projects")]
[UseAuthorization(typeof(ProjectPermissionMiddleware))]
public sealed class ProjectsController : ControllerBase
{
    [HttpGet("/[projectId]")]
    [Authorization(Permission = "read:projects")]
    public Task<ProjectResponse> Get(string ProjectId)
    {
        return Task.FromResult(new ProjectResponse { ProjectId = ProjectId });
    }
}

public sealed class ProjectResponse
{
    public string ProjectId { get; set; } = string.Empty;
}

public sealed class ProjectPermissionMiddleware : AuthorizationMiddleware<PermissionAuthorizationRequirement>
{
    public override Task Authorize(AuthorizationContext Context, PermissionAuthorizationRequirement Requirement)
    {
        Context.Authorized = Context.HttpContext?.User is not null
            && Requirement.Permission == "read:projects";

        return Task.CompletedTask;
    }
}
```

Authorization middleware declared through `[UseAuthorization]` is constructed through `Router.ServiceProvider`, so constructor injection works there in the same way it does for controllers and middleware.

## How the flow works

* `[UseAuthorization]` registers one or more controller-level authorization middleware types
* `[Authorization]` adds requirements to individual methods
* `AuthorizationMiddleware<T>` only receives requirements of type `T`
* The middleware must set `AuthorizationContext.Authorized = true`
* Rejected requirements return `403 Forbidden`

You can apply `[UseAuthorization]` more than once to the same controller when different requirement types should be evaluated by different middleware classes.

## Roles and permissions together

```csharp theme={null}
[Controller]
[Route("/admin")]
[UseAuthorization(typeof(ProjectPermissionMiddleware))]
[UseAuthorization(typeof(AdminRoleMiddleware))]
public sealed class AdminController : ControllerBase
{
    [HttpGet("/dashboard")]
    [Authorization(Permission = "read:projects")]
    [Authorization(Role = "Administrator")]
    public Task<DashboardResponse> Get()
    {
        return Task.FromResult(new DashboardResponse { Message = "authorized" });
    }
}
```

## Low-level equivalent

```csharp theme={null}
Router.UseAuthorization("/projects");
Router.RegisterMiddleware("/projects", new ProjectPermissionMiddleware().Invoke);
Router.SetAuthorization(
    HttpMethodType.Get,
    "/projects/[projectId]",
    new PermissionAuthorizationRequirement("read:projects"));
```

## When to choose attributes vs manual setup

**Choose attributes when:**

* The route is already controller-based
* The requirement belongs naturally to one endpoint
* You want the policy close to the action method

**Choose the manual API when:**

* You register low-level endpoints directly
* You need fine-grained control over pipeline wiring
* You build a reusable router module outside controller discovery

<Note>
  For intentional HTTP failures inside authorization or middleware, throw `HttpException` subclasses such as `ForbiddenException`. Unexpected exceptions are converted into `500` responses by the router's exception boundary.
</Note>

## What to read next

[Advanced patterns](/neuron-development/first-party-packages/neuron-http-router/advanced-patterns) covers raw request handling, manual endpoints, and parameter-name codecs.
