Skip to main content

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

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

[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;
    }
}

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

Roles and permissions together

[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

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:
  • Registering low-level endpoints directly
  • You need fine-grained control over pipeline wiring
  • Building a reusable router module outside controller discovery
Advanced Patterns covers raw request handling, manual endpoints, and parameter-name codecs.