Authorization
Authorization is a set of application-defined rules evaluated against a SecurityContext. A policy can check roles, permissions, ownership, tenant membership, resource state, or any other condition. Policies are ordinary injectable classes; the package does not introduce a fixed role or permission model.
Write a policy
import { Injectable } from '@axisparkjs/di';
import { AuthorizationDecision, AuthorizationPolicy, SecurityContext } from '@axisparkjs/security';
import { Principal } from './principal';
@Injectable()
export class AdminPolicy extends AuthorizationPolicy {
async authorize(context: SecurityContext<Principal>): Promise<AuthorizationDecision> {
const authorized = context.data?.role === 'admin';
return authorized
? { policy: AdminPolicy, authorized: true }
: {
policy: AdminPolicy,
authorized: false,
reason: 'An administrator role is required'
};
}
}
An allow decision contains the policy class and authorized: true. A denial also contains a reason, which is retained in the context and included in AuthorizationError.causes. Since policies are resolved by dependency injection, they can use services such as permission repositories or resource access services.
Apply policies with @Secured()
@Controller('/documents')
@Secured({ policies: [ActivePrincipalPolicy] })
export class DocumentController {
@Get('/:ownerId')
@Secured({ policies: [DocumentOwnerPolicy] })
read() {
return this.documents.read();
}
@Get('/admin/export')
@Secured({ policies: [AdminPolicy] })
export() {
return this.documents.export();
}
}
The class decorator marks all handlers as secured and adds class policies. Method decorators add policies to individual handlers. A method with both sets is evaluated in this order:
- Class policies, in declaration order.
- Method policies, in declaration order.
All policies run, including policies after the first denial. The engine records every decision and allows the handler only when all decisions allow it (logical AND). This preserves diagnostics for error mapping and logging.
Use @Secured({ policies: [] }) on a class or method when authentication is required but no additional policy is needed. With no policy metadata at all, authorization starts as allowed; the authentication guard still checks @Secured() metadata independently.
Policy composition
Each policy is a class, so rules can be reused and composed across handlers. For example, a controller can require an active principal at class level, then a method can require ownership. A different method can add an administrator rule. The same policy can be injected with application services and does not need to know which controller declared it.
SecurityContext<T> carries data?: T, the opaque value returned by the successful authenticator. Choose a type that represents your app's identity, such as a user principal, service account, or verified token claims. The policy can also inspect the transport's execution context; narrow it to HttpContext, a message context, or another transport type when needed.