NestJS adapter
WIPNestJS guard + module + controller. Decorator-driven session resolution.
Setup
auth.module.ts
import { Module } from '@nestjs/common'
import { AuthRootModule } from '@gentleduck/auth/server/nestjs'
import { auth } from './lib/auth'
@Module({
imports: [AuthRootModule.forRoot({ auth })],
})
export class AuthModule {}
This registers the controller at /auth/* and exposes a guard plus
decorators.
Guard a route
account.controller.ts
import { Controller, Get } from '@nestjs/common'
import { AuthGuard, CurrentIdentity } from '@gentleduck/auth/server/nestjs'
import type { AuthIdentity } from '@gentleduck/auth/core'
@Controller('account')
@UseGuards(AuthGuard)
export class AccountController {
@Get()
async me(@CurrentIdentity() identity: Identity) {
return identity
}
}
AuthGuard calls auth.resolveSession() on the incoming request; if
no session, the guard throws UnauthorizedException (HTTP 401).
@CurrentIdentity() injects the resolved identity into the handler.
Add @CurrentSession() to get the session as well.
AAL gate
import { RequireAal } from '@gentleduck/auth/server/nestjs'
@Controller('admin')
@UseGuards(AuthGuard)
export class AdminController {
@Post('delete')
@RequireAal('aal2') // throws AUTH/AAL_INSUFFICIENT otherwise
async delete() { /* ... */ }
}
For freshness checks (sensitive irreversible action), pair with
@RequireFreshness({ withinMs: 5 * 60 * 1000 }).
Custom error mapping
auth.filter.ts
import { ArgumentsHost, Catch, ExceptionFilter } from '@nestjs/common'
import { AuthError } from '@gentleduck/auth/core'
@Catch(AuthError)
export class AuthErrorFilter implements ExceptionFilter {
catch(err: AuthError, host: ArgumentsHost) {
const ctx = host.switchToHttp()
const reply = ctx.getResponse()
reply.status(err.status).json(err.toJSON())
}
}
Register it globally:
app.useGlobalFilters(new AuthErrorFilter())
CSRF
For state-mutating routes, install CsrfGuard upstream of AuthGuard:
@Controller('api')
@UseGuards(CsrfGuard, AuthGuard)
export class ApiController { /* ... */ }
CsrfGuard is a no-op for bearer/JWT routes (no cookies, no CSRF).