@playstack/nest-auth
NestJS guards and request decorators for Playstack sessions and CSRF transport.
Free. MIT licensed. Check preview availability before installing. See package access.
@playstack/nest-auth connects @playstack/auth session validation and its fixed CSRF transport to NestJS guards and decorators.
Install
After confirming preview access, install the package at your application's shared Playstack version:
npm install --save-exact @playstack/nest-auth@0.1.0-beta.1Check the peer requirements below before choosing a runtime or provider.
Install and compose
PlaystackAuthModule.forRoot({
sessions,
allowedOrigins: ['https://app.example'],
})Use forRootAsync({ imports, inject, useFactory }) when the session strategy depends on other Nest providers.
@UseGuards(PlaystackAuthGuard, PlaystackCsrfGuard)
@Post('/profile')
update(@CurrentSession() session: SessionClaims) {}
@Public()
@Get('/health')
health() {}Configuration reference
NestAuthOptions property | Required | Purpose |
|---|---|---|
sessions | Yes | Any structural SessionStrategy, or a factory ({ devices }) => SessionStrategy that receives the injected device validator. |
allowedOrigins | Yes | Exact origins accepted for cookie-authenticated unsafe requests. |
devices | No | A DeviceSessionValidator such as the @playstack/devices service; also resolvable from the NEST_DEVICE_SESSION_VALIDATOR provider. |
guards | No | The composition PlaystackGuardStack runs: 'cookie' (default), 'bearer', or guard classes in order. |
globalGuards | No | Registration only: install the composed stack as a global guard; routes opt out with @Public(). |
imports | No | forRoot only: modules exporting NEST_DEVICE_SESSION_VALIDATOR or application guards. |
sessionCookieName | No | Host-only cookie name; must begin __Host-. |
csrfCookieName | No | Synchronizer cookie name; must begin __Host-. |
csrfHeaderName | No | Header carrying the synchronizer token. |
PlaystackAuthGuard accepts the host-only cookie or a strict bearer token and attaches only SessionClaims as request.playstackSession. A validation failure thrown by the strategy, such as a revoked device, is answered with 401; retryable persistence failures keep their original error. PlaystackCsrfGuard validates Origin plus synchronizer token for cookie-authenticated unsafe methods; bearer requests do not use ambient browser credentials and bypass CSRF.
Split-origin cookie routes
When the page and the API are different origins, the page cannot read a CSRF cookie set on the API origin, so the synchronizer-token guards do not apply. PlaystackOriginGuard is the defence for that profile: an unsafe browser request must present an Origin from allowedOrigins and, when the browser sends it, a Sec-Fetch-Site that is not cross-site. A request with no Origin, no Fetch Metadata and no cookie carries no ambient credential and passes, so a CLI, a mobile app or a server can call the same routes with a bearer token or explicit credentials. isBrowserRequest(request) exposes that decision for controllers that choose a transport per client. A refusal answers 403 with { error: 'origin_not_allowed' }.
| Guard | Profile |
|---|---|
PlaystackCsrfGuard | Same-origin cookie sessions with a synchronizer token; bearer requests are exempt. |
PlaystackCookieCsrfGuard | Cookie-mutating routes on that profile; never bearer-exempt. |
PlaystackOriginGuard | Split-origin bearer contract; browser requests need an allowed Origin, non-browser requests pass. |
Registered devices via dependency injection
@playstack/devices is not a dependency of this package. Its service satisfies the DeviceSessionValidator contract from @playstack/auth, so the module accepts it through Nest injection and passes it to a session factory.
import { Module } from '@nestjs/common'
import { databaseSessions } from '@playstack/auth'
import { NEST_DEVICE_SESSION_VALIDATOR, PlaystackAuthModule } from '@playstack/nest-auth'
@Module({
providers: [{ provide: NEST_DEVICE_SESSION_VALIDATOR, useValue: devices }],
exports: [NEST_DEVICE_SESSION_VALIDATOR],
})
class DevicesModule {}
PlaystackAuthModule.forRoot({
imports: [DevicesModule],
sessions: ({ devices }) =>
databaseSessions({ persistence, crypto, events, clock, ids, deviceValidator: devices, requireDevice: true }),
allowedOrigins: ['https://app.example'],
})With forRootAsync, inject the service and return it as devices, or export the provider from an imported module; either way the sessions factory receives it and NEST_AUTH_OPTIONS exposes the resolved validator. Register sessions.deviceRevocationHandler() for devices.device.revoked on the shared emitter so revoking a device revokes its sessions in the same transaction.
Composing guards
The application composes the guards; the package never installs one on its own. Name a default composition by transport profile and place PlaystackGuardStack where it belongs, install that composition globally with globalGuards: true and opt routes out with @Public(), or list your own layering of package guards, other Playstack bindings and application guards.
PlaystackAuthModule.forRoot({ sessions, allowedOrigins, guards: 'bearer' })
@UseGuards(PlaystackGuardStack)
@Controller('accounts')
export class AccountsController {}
// Your own order, mixing bindings and application guards:
PlaystackAuthModule.forRoot({
sessions,
allowedOrigins,
guards: [PlaystackOriginGuard, TenantGuard, PlaystackAuthGuard, PlaystackAccountGuard],
})'cookie' is PlaystackCsrfGuard then PlaystackAuthGuard; 'bearer' is PlaystackOriginGuard then PlaystackAuthGuard; playstackGuardStacks exports both for spreading into @UseGuards. The stack resolves each guard once from the application's providers, or constructs it with its dependencies when it is not registered, evaluates them in order, and stops at the first denial. A bad composition fails at bootstrap. Every guard stays exported for individual placement.
Boundary
The underlying SessionStrategy is the replacement seam. The adapter does not own users, accounts, provider normalization, persistence, or authorization, and it never installs a guard the application did not ask for. Applications control guard placement and ordering.
Authorization and credentials are separate surfaces
The package includes optional device-authorization and credential-route integration resources in addition to session/refresh/sign-out composition. Templates are application-owned wiring: configure registration policy, input validation, consent, CSRF/raw transport behavior, rate limits and required transactional adapters before enabling routes. Device and authorization-code success responses are not replayable recovery stores.
API entry points and requirements
Reference snapshot: @playstack/nest-auth@0.1.0-beta.1. Import only the entry point your runtime needs. Paths below are relative to the installed package; use Go to Definition in your editor to inspect exact parameters, return types and overloads. Do not import the declaration-file paths directly.
| Public entry point | Declaration file |
|---|---|
@playstack/nest-auth | ./dist/index.d.ts |
@playstack/nest-auth/device | ./dist/device.d.ts |
@playstack/nest-auth/package.json | No TypeScript declaration (asset or metadata export). |
Node.js engine requirement: >=20. This is not a claim that every entry point works in browsers or Workers.
Peer dependencies
Keep existing framework versions that satisfy these ranges. Install optional peers only when using the corresponding adapter. The package manager resolves ordinary dependencies separately.
| Peer | Compatible range | When needed |
|---|---|---|
@nestjs/common | ^10.0.0 || ^11.0.0 | Required by the package. |
@nestjs/core | ^10.0.0 || ^11.0.0 | Required by the package. |
@playstack/auth | 0.1.0-beta.1 | Required by the package. |
@playstack/core | 0.1.0-beta.1 | Required by the package. |
reflect-metadata | ^0.1.13 || ^0.2.0 | Required by the package. |
rxjs | ^7.0.0 | Required by the package. |
For a complete first program, start with Getting started. For API lookup and partial-example conventions, see Reading the reference. Provider failures, lifecycle requirements and application responsibilities remain described in the guide above; types alone do not establish production safety.