NestJS
@authcore/nestjs is a dynamic NestJS module that registers all auth routes and exposes guards and decorators for protecting your controllers.
Installation
npm install @authcore/nestjs @authcore/prisma-adapterPeer dependencies (already present in any NestJS project):
@nestjs/common^10 or ^11@nestjs/core^10 or ^11reflect-metadata^0.1.13 or ^0.2.0
Module Setup
Import AuthModule in your root AppModule:
// app.module.ts
import { Module } from '@nestjs/common'
import { AuthModule } from '@authcore/nestjs'
import { prismaAdapter } from '@authcore/prisma-adapter'
import { PrismaClient } from '@prisma/client'
const prisma = new PrismaClient()
@Module({
imports: [
AuthModule.register({
db: prismaAdapter(prisma),
session: { strategy: 'jwt', secret: process.env.AUTH_SECRET! },
}),
],
})
export class AppModule {}This registers all auth routes under /auth and makes guards available globally.
Protecting Routes
Use AuthGuard on any controller or route handler. The authenticated user is injected with @CurrentUser():
import { Controller, Get, UseGuards } from '@nestjs/common'
import { AuthGuard, CurrentUser } from '@authcore/nestjs'
import type { PublicUser } from '@authcore/nestjs'
@Controller('dashboard')
@UseGuards(AuthGuard)
export class DashboardController {
@Get()
getDashboard(@CurrentUser() user: PublicUser) {
return { user }
}
}Role-Based Access Control
Pair RolesGuard with the @Roles() decorator. Always apply AuthGuard first so request.user is populated:
import { Controller, Get, UseGuards } from '@nestjs/common'
import { AuthGuard, RolesGuard, Roles, CurrentUser } from '@authcore/nestjs'
import type { PublicUser } from '@authcore/nestjs'
@Controller('admin')
@UseGuards(AuthGuard, RolesGuard)
@Roles('admin')
export class AdminController {
@Get()
getAdmin(@CurrentUser() user: PublicUser) {
return { message: 'Admin area', user }
}
}Enable RBAC in AuthModule.register():
AuthModule.register({
db: prismaAdapter(prisma),
session: { strategy: 'jwt', secret: process.env.AUTH_SECRET! },
rbac: { defaultRole: 'user' },
})Optional Authentication
Use AuthOptionalGuard on routes that work for both authenticated and anonymous users:
import { Controller, Get, UseGuards } from '@nestjs/common'
import { AuthOptionalGuard, CurrentUser } from '@authcore/nestjs'
import type { PublicUser } from '@authcore/nestjs'
@Controller('public')
export class PublicController {
@Get()
@UseGuards(AuthOptionalGuard)
getPublic(@CurrentUser() user: PublicUser | undefined) {
return { user: user ?? null }
}
}Cookie Mode
Set useCookies: true and register cookie-parser middleware in main.ts. NestJS cookie support requires @nestjs/platform-express (the default).
// main.ts
import { NestFactory } from '@nestjs/core'
import cookieParser from 'cookie-parser'
import { AppModule } from './app.module'
async function bootstrap() {
const app = await NestFactory.create(AppModule)
app.use(cookieParser())
await app.listen(3000)
}
bootstrap()// app.module.ts
AuthModule.register({
db: prismaAdapter(prisma),
session: {
strategy: 'jwt',
secret: process.env.AUTH_SECRET!,
cookieName: 'my_token', // optional; default 'authcore_token'
},
useCookies: true,
})When useCookies is true:
POST /auth/register,POST /auth/login,POST /auth/accept-invitationset the cookie and return{ user }(no token in body).POST /auth/logoutclears the cookie.AuthGuardandAuthOptionalGuardfall back to reading the cookie if noAuthorization: Bearer ...header is present.
With Email Features & Invitations
import { resendAdapter } from '@authcore/resend-adapter'
AuthModule.register({
db: prismaAdapter(prisma),
session: { strategy: 'jwt', secret: process.env.AUTH_SECRET! },
email: {
provider: resendAdapter(process.env.RESEND_API_KEY!),
from: 'auth@yourdomain.com',
},
features: ['emailVerification', 'passwordReset', 'invitation'],
rbac: { defaultRole: 'user' },
baseUrl: 'https://yourdomain.com',
})API Reference
AuthModule.register(options)
All options from @authcore/core configuration are accepted, plus:
| Option | Type | Default | Description |
|---|---|---|---|
baseUrl | string | '' | Base URL used to build links in auth emails |
useCookies | boolean | false | Set/clear an httpOnly cookie on register/login/logout/accept-invitation instead of returning the token in the response body |
Cookie name is read from session.cookieName (default 'authcore_token'). See the Configuration reference for the full session shape.
Guards
| Guard | Description |
|---|---|
AuthGuard | Requires a valid JWT. Attaches the user to request.user. Throws UnauthorizedException (401) if no token is present or the token is invalid. |
AuthOptionalGuard | Attaches request.user if a valid token is present. Never rejects the request. |
RolesGuard | Checks request.user.role against @Roles(). Throws ForbiddenException (403) if the role is not allowed. Must be used after AuthGuard. |
Decorators
| Decorator | Description |
|---|---|
@CurrentUser() | Parameter decorator — extracts the authenticated user from the request |
@Roles('admin', 'editor') | Sets the required roles for a route or controller |
@Public() | Marks a route as public, bypassing AuthGuard |
Routes
All routes are mounted under /auth by default:
| Method | Route | Body | Description |
|---|---|---|---|
| POST | /auth/register | { email, password } | Register a new user |
| POST | /auth/login | { email, password } | Log in, returns JWT |
| POST | /auth/logout | — | Invalidate the session |
| GET | /auth/me | — | Return the current user |
| POST | /auth/verify-email | { token } | Verify email address |
| POST | /auth/forgot-password | { email } | Send password reset email (always 200) |
| POST | /auth/reset-password | { token, password } | Reset password |
| POST | /auth/invite | { email, role? } | Send an invitation |
| POST | /auth/accept-invitation | { token, password } | Accept an invitation and set a password |
| POST | /auth/refresh | { refreshToken } (or cookie) | Rotate the refresh token; returns new { user, token, refreshToken } |
| POST | /auth/revoke | { refreshToken } (or cookie) | Revoke a refresh token (idempotent) |
Refresh Tokens (0.10+)
register, login, acceptInvitation, and refresh all return { user, token, refreshToken } in api mode (or set httpOnly cookies in cookie mode). Configure with session.refreshExpiresIn (default '30d'). See Refresh Tokens.
CSRF (0.10+, cookie mode)
Set session.csrf: true and bind CsrfGuard globally in main.ts:
import cookieParser from 'cookie-parser'
import { CsrfGuard } from '@authcore/nestjs'
const app = await NestFactory.create(AppModule)
app.use(cookieParser())
app.useGlobalGuards(app.get(CsrfGuard))State-changing requests must include the X-CSRF-Token header matching ${cookieName}_csrf. See CSRF.