This guide explains how to plug the Passkey ApiModule (src/api/) into your own NestJS backend. It focuses only on what to copy and what to configure. Endpoint details and flows live in the main README.
- Copy the module code: copy the entire
src/api/directory into your NestJS project.- You get:
ApiModule(Nest module)ApiController(passkey + demo OTP endpoints)CorbadoService(talks to Corbado Backend API)- DTOs, filters, exceptions, decorators, guard, session manager.
- You get:
- Demo-only parts:
signUpOrLogin+UserRepository- In a real app you will usually:
- Replace them with your own login + user model, or
- Delete them and only keep the passkey endpoints.
Install the required runtime dependencies:
npm install @corbado/node-sdk jsonwebtoken class-validator class-transformer lowdb uuid dotenvNote:
axiosis used by the CorbadoService but is already included as a transitive dependency of@corbado/node-sdk, so you don't need to install it separately.
Wire the module into your main AppModule. The example below uses @nestjs/config; you can also follow the simpler process.env‑based example in this repo’s app.module.ts if you prefer.
import { Module } from '@nestjs/common';
import { ConfigModule, ConfigService } from '@nestjs/config';
import { ApiModule } from './api';
@Module({
imports: [
ConfigModule.forRoot(),
ApiModule.forRootAsync({
imports: [ConfigModule],
useFactory: (config: ConfigService) => ({
projectId: config.get<string>('CORBADO_PROJECT_ID')!,
apiSecret: config.get<string>('CORBADO_API_SECRET')!,
backendApiUrl:
config.get<string>('CORBADO_BACKEND_API_URL') ||
'https://backendapi.corbado.io',
rpId: config.get<string>('RP_ID')!,
rpName: config.get<string>('RP_NAME') || 'My App',
jwtSecret: config.get<string>('JWT_SECRET')!,
sessionTokenExpirySeconds: 60 * 60 * 12, // demo default: 12h
}),
inject: [ConfigService],
}),
],
})
export class AppModule {}Config fields (high‑level):
projectId,apiSecret,backendApiUrl: Corbado project + backend API.rpId,rpName: WebAuthn Relying Party config (must match your app/platform setup).jwtSecret,sessionTokenExpirySeconds: used bySessionManagerServiceto sign and validatesessionTokens.
Use whatever config mechanism you already have (env files, Vault, etc.); the important part is that those values are available to ApiModule.
Assuming you already have a working NestJS app, you only need to extend your existing main.ts:
- Imports:
ValidationPipefrom@nestjs/common(if not already used).ApiExceptionFilterfrom the copied./apibarrel.
// main.ts
import { ValidationPipe } from '@nestjs/common';
import { ApiExceptionFilter } from './api';
async function bootstrap() {
const app = await NestFactory.create(AppModule);
// Add (or extend) global validation
app.useGlobalPipes(
new ValidationPipe({
whitelist: true,
forbidNonWhitelisted: true,
transform: true,
}),
);
// Add the custom API exception filter
app.useGlobalFilters(new ApiExceptionFilter());
// ... keep your existing CORS / listen / other setup
}- Validation: required so the DTOs in
src/api/dto/*work as intended. ApiExceptionFilter: ensures exceptions thrown inside the module are returned in a consistent JSON format.
- Identifier: the module consistently uses
identifieras your primary user ID (email, phone, or internal ID). Make sure this matches what your own auth/user system uses. - Session:
SessionManagerServiceissues and verifies a demosessionToken(JWT) usingjwtSecretandsessionTokenExpirySeconds. - Guard:
SessionManagerGuardis used on protected routes insidesrc/apiand expects an authenticated user via thatsessionToken. You can keep it, or replace it with your own guard while keeping the same contract.
For endpoint list and detailed flows, see the main README.