Guards
Control access to routes based on conditions like authentication and roles.
Guards determine whether a request should be handled by the route handler. They are the recommended way to implement authentication and authorization in MiiaJS.
CanActivate interface
A guard is a class that implements the CanActivate interface:
import type { CanActivate, RequestContext } from '@miiajs/core'
class AuthGuard implements CanActivate {
canActivate(ctx: RequestContext): boolean | Promise<boolean> {
const token = ctx.req.headers.get('authorization')
return !!token
}
}
- Return
trueto allow the request - Return
falseto reject with403 Forbidden - Throw an
HttpExceptionfor a custom error response
Applying guards
Per route
import { UseGuard } from '@miiajs/core'
@Controller('/items')
class ItemController {
@Delete('/:id')
@UseGuard(AuthGuard)
remove(ctx: RequestContext) {
return { deleted: true }
}
}
Per controller
@Controller('/admin')
@UseGuard(AuthGuard)
class AdminController {
@Get('/dashboard')
dashboard() {
return { stats: {} }
}
}
Global
const app = new Miia()
.useGuard(AuthGuard)
.register(AppModule)
Guards with DI
Guards can use dependency injection:
@Injectable()
class AuthGuard implements CanActivate {
private tokenService = inject(TokenService)
async canActivate(ctx: RequestContext): Promise<boolean> {
const header = ctx.req.headers.get('authorization')
if (!header?.startsWith('Bearer ')) {
throw new UnauthorizedException()
}
const user = await this.tokenService.verify(header.slice(7))
if (!user) throw new UnauthorizedException()
ctx.user = user
return true
}
}
Parameterized guards
Create guard factories for reusable logic:
function Roles(...roles: string[]) {
class RolesGuard implements CanActivate {
canActivate(ctx: RequestContext) {
return roles.includes(ctx.user?.role)
}
}
return RolesGuard
}
Combine multiple guards:
@Delete('/:id')
@UseGuard(AuthGuard, Roles('admin'))
remove(ctx: RequestContext) {
return { deleted: true }
}
Guards execute in order. If AuthGuard fails, Roles is never called.
Guard execution order
Global guards (app.useGuard())
-> Controller guards (@UseGuard on class)
-> Route guards (@UseGuard on method)
-> Route handler