Docs Home | Previous: Spec-Only Mode | Next: Interceptors
Use guards to allow, deny, or short-circuit requests before controller execution. Guards run after middleware and before interceptors.
After middleware
|
v
+-------------------------------------------+
| Global guards |
| array order from createApp |
+-------------------------------------------+
|
v
+-------------------------------------------+
| Controller guards |
| @UseGuards on the class |
+-------------------------------------------+
|
v
+-------------------------------------------+
| Method guards |
| @UseGuards on the method |
+-------------------------------------------+
|
v
+-------------------------------------------+
| Security guards |
| applied for @Security routes |
+-------------------------------------------+
|
+--> false -> 403 Forbidden
+--> Response -> short-circuit
+--> throw -> errorFormatter
|
v
Continue to interceptors
Guards are evaluated sequentially. If any guard denies access, the remaining guards and the controller method are skipped.
@Injectable()
class RequireAdminGuard {
canActivate({ request }: GuardContext) {
return request.headers.get("x-role") === "admin";
}
}Security guards receive additional context about the security scheme and required scopes:
@Injectable()
class BearerAuthGuard {
canActivate({ request, scheme, scopes }: SecurityGuardContext) {
const token = request.headers.get("authorization")?.replace("Bearer ", "");
if (!token) return false;
// verify token and check scopes...
return true;
}
}Every guard receives a context object with request details:
+---------------------------------------------------------------+
| GuardContext |
| |
| request: Request raw request |
| params: Record<string, string> path params |
| query: Record<string, string | string[]> query data |
| headers: Record<string, string | undefined> headers |
| body: unknown parsed body |
| className: string controller |
| methodName: string handler |
+---------------------------------------------------------------+
+---------------------------------------------------------------+
| SecurityGuardContext extends GuardContext |
| |
| scheme: string security scheme name, e.g. bearerAuth |
| scopes: string[] required scopes from @Security |
+---------------------------------------------------------------+
// Route or Controller level — guard all methods
@Route("/admin")
@UseGuards(RequireAdminGuard)
class AdminController extends Controller {
@Get("/stats")
stats() { return { ok: true }; }
}
// Method level — guard a single endpoint
@Route("/items")
class ItemsController extends Controller {
@Delete("/:id")
@UseGuards(RequireAdminGuard)
remove(@Param("id") id: string) { ... }
}
// Global level — guard every route in the app
const app = createApp({
guards: [RateLimitGuard],
// ...
});Map @Security scheme names to guard classes in createApp:
const app = createApp({
schema: classValidator(),
controllers: [AdminController],
securityGuards: {
bearerAuth: BearerAuthGuard,
},
});When a route has @Security("bearerAuth"), the framework instantiates BearerAuthGuard in the request scope and calls canActivate() with the scheme name and scopes.
| Return | Effect |
|---|---|
true or undefined |
Continue to next guard or controller |
false |
Deny with 403 Forbidden |
Response |
Short-circuit with that custom response |
throw |
Error flows through errorFormatter |
See examples/06_guards/server.ts and examples/06_guards/controllers.ts.