Skip to main content

How It Works

nauth-toolkit lives inside your backend. You configure it once and it mounts the auth endpoints for you, over services you can also call directly. No separate process, no external API, no SDK calls over the network.

Where It Lives​

The mounted routes call nauth services — and so does any route you write yourself. nauth reads and writes to your database. Your frontend talks to your backend as normal — nothing in the middle.

Authentication first — authorization is pluggable

nauth-toolkit verifies identity and issues tokens. It defines no roles or permissions of its own, so application-level access control stays yours.

For its own administrative operations it ships a contract: supply an IAuthorizationProvider and every privileged service method consults it. Without one, admin routes refuse to mount.

What You Configure​

Two things, once, at startup:

What You Write​

Backend — configuration, not controllers​

The auth endpoints ship with the toolkit. You add a routes block, and nauth mounts sign-up, sign-in, refresh, challenges, profile, MFA, social linking, sessions and device trust — handling password hashing, JWT issuance, session management, rate limiting and audit logging behind each one.

src/config/auth.config.ts
routes: [{ prefix: 'auth' }],

You write a route handler only when you want to change one. Exclude its key and declare just that route, delegating to the same service the shipped route would have called:

routes: [{ prefix: 'auth', exclude: ['login'] }],

See Authentication Routes for mounting, overriding and surface reduction, and Shipped Routes for the full table.

The services behind those routes​

ServiceResponsibility
AuthServiceSignup, login, logout, password reset, token refresh, email/phone verification
MFAServiceEnroll and verify TOTP, SMS, email, and passkey methods
SocialAuthServiceGoogle, Apple, Facebook — redirect flows and native mobile token verification

Frontend — SDK with challenge routing​

The client SDK (@nauth-toolkit/client) handles token storage, CSRF, and auth state. Your frontend calls SDK methods and responds to challenges:

// Login — SDK returns tokens or a challenge
const result = await auth.login(email, password);

// Challenge? Route the user to the right screen
if (result.challengeName) {
// 'MFA_REQUIRED', 'VERIFY_EMAIL', 'MFA_SETUP_REQUIRED', etc.
navigateToChallenge(result);
return;
}

// No challenge — user is authenticated
navigateToDashboard();

Challenges can chain: signup may require email verification → then MFA setup → then login MFA. The SDK tracks the session across steps. When the final challenge is resolved, tokens are issued.

→ Challenge System — all challenge types and how to resolve them

Request Processing Pipeline​

Every request passes through a fixed handler chain before reaching the route handler — whether that is a mounted route or one you wrote. The order is the same across all frameworks; only the registration mechanism differs:

OrderHandlerResponsibility
1ClientInfoHandlerExtracts IP, user-agent, device token, and geo data from the request. Initializes the AsyncLocalStorage context that all downstream handlers depend on.
2CsrfHandlerValidates the CSRF token when token delivery uses cookies or hybrid mode. Skipped for JSON-only delivery.
3AuthHandlerValidates the JWT access token and attaches the authenticated user to the request context. Routes marked @Public() skip validation.
4TokenDeliveryHandlerResponse interceptor — rewrites the outgoing response to deliver tokens via Set-Cookie headers (cookie/hybrid mode) or leaves them in the JSON body (JSON mode).
Framework specifics
  • NestJS — Handlers 1-3 run as global guards (NAuthContextGuard → CsrfGuard); handler 4 runs as a global interceptor (CookieTokenInterceptor).
  • Express — Handlers 1-3 register as middleware via app.use(); handler 4 registers via registerResponseInterceptor().
  • Fastify — Handlers 1-3 register as onRequest/preHandler hooks; handler 4 registers as an onSend hook. Each hook restores the AsyncLocalStorage context from the request object.

Framework Support​

nauth-toolkit has a framework-agnostic core. The same services work across all three integrations:

FrameworkHow you add it
NestJSImport AuthModule.forRoot() — guards and decorators are wired automatically
ExpressCall NAuth.create() with ExpressAdapter — middleware registered on your app
FastifyCall NAuth.create() with FastifyAdapter — hooks registered on your instance

→ Quick Start — get running in minutes

What's Next​