Skip to main content
Authorization filters complement Nest guards. Use a guard for authentication and coarse endpoint access; use an authorizer for record-level visibility.

Inline authorizer​

Decorate the response DTO with @Authorize. The first argument is the HTTP request and the second describes the generated operation.
todo-item.dto.ts
For collection requests, the authorization filter is merged with the client filter. For single-record, update, and delete requests it is passed as an additional service filter, preventing access to records owned by another user.

Authorizer class​

Use an injectable class for more involved rules:
todo-item.authorizer.ts
todo-item.dto.ts
AuthorizationContext contains:
  • operationName: generated controller method name, such as queryMany or updateOne.
  • operationGroup: read, create, update, delete, or export.
  • readonly: whether the operation does not modify data.
  • many: whether the operation can affect multiple records.
The module registers authorizer providers for DTOs listed in either endpoints or dtos.

Add a guard​

Ensure the request has a user before the authorizer runs:
Guards and authorizers can also be scoped through the read, create, update, delete, and export operation options.

Applying auth filters on creation​

The authorizer runs for createOne, but by default the filter it returns is not enforced against the request body; the authorizer can only reject a create by throwing, as shown above. Set validateWithAuthFilter in the create options to also enforce the filter:
The filter is passed to the query service, which evaluates it in JS against the request body before saving. A body that does not match the filter, for example an ownerId different from request.user.id, is rejected with a BadRequestException (HTTP 400) and the message Entity does not meet creation constraints. The option only takes effect when the authorizer resolves a filter for the create operation group; if no authorizer is registered for the DTO, or it returns no filter for create operations, the option is a no-op.
The filter is evaluated in JS against the flat request body. This has a few limitations:
  • Filter clauses on relations, or on fields populated by the database (such as createdAt, generated ids, or column defaults), cannot be checked and will not match.
  • The filter is evaluated against the fields present on the body: a field that is missing from the body fails positive operators (eq, in, like) but passes negated operators (neq, notIn, notLike), so negated filters cannot reliably constrain fields the client omits.
  • Enforcement happens in the query service, so a custom service that overrides createOne(item) or createMany(items) without accepting and forwarding the new opts parameter will silently skip the check.