Authentication comes first
Authorization requirements only make sense once the router knows which authentication schemes it should advertise.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
[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 methodsAuthorizationMiddleware<T>only receives requirements of typeT- The middleware must set
AuthorizationContext.Authorized = true - Rejected requirements return
403 Forbidden
[UseAuthorization] more than once to the same controller when different requirement types should be evaluated by different middleware classes.
Roles and permissions together
Low-level equivalent
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
- You register low-level endpoints directly
- You need fine-grained control over pipeline wiring
- You build a reusable router module outside controller discovery
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.