Setup Checklist
The boot-time wiring that catches every team the first time.
Read this once, get it right once. The list of things every NestJS app needs to wire up before NestAuthModule works.
A complete main.ts
And your AppModule:
The eleven boot-time gotchas
-
./load-envmust import beforeNestFactory.create. dotenv readsprocess.envsynchronously at import time. IfNestAuthModulereadsJWT_SECRETbefore dotenv runs, you'll getundefinedand signed tokens won't validate. -
cookieParser()is mandatory for cookie-mode sessions. Without it, the library can't read the auth cookies and every request looks unauthenticated. -
CORS
allowedHeadersmust includex-access-token-typeandnest_auth_device_trust. Browsers send a preflightOPTIONSfor any request with custom headers; if the response doesn't allow them, the actual request never goes out. Auto-refresh appears to "not work" because it never gets a chance to fire. -
CORS
credentials: true— required for cookie mode. The browser drops cookies on cross-origin requests otherwise. -
No
origin: '*'withcredentials: true— the browser rejects this combination. Use an explicit allowlist. -
ValidationPipewithforbidNonWhitelisted: trueis strict. It rejects unknown fields. The library's signup DTO is open-ended (extra fields land on theUserRegisteredEventpayload), so usewhitelist: trueonly on your DTOs, or usewhitelist: truewithoutforbidfor signup-style endpoints. The setup above is the safe default; tighten per-controller. -
Register
AuthExceptionFilterglobally. Without it, the library's structured exceptions become generic NestJS 500-class errors with noerrorCodefield — your frontend can't branch on the failure type. -
EventEmitterModule.forRoot()must be imported before any@OnEventlistener can fire. This is the most common silent failure: events look like they're emitting (no errors) but no listener runs. The fix is one line inAppModule. -
TypeORM needs both
forRootandforFeature(NestAuthEntities)—forRootregisters the data source,forFeaturemakes the entities injectable in services. The library uses both internally. -
synchronize: trueis for development only. Production should use migrations. See Database Setup. -
Helmet's
crossOriginEmbedderPolicyblocks OAuth popups. Disable it (or carefully whitelist the providers' origins) if you support social login.
Verification
Boot the app, then:
If the protected route returns the user, you're set.
Next
- Database Setup — the three install paths.
- Environment & Secrets.
- Quickstart — Backend.