@bitwild/rockets-auth
Version:
Rockets Auth - Complete authentication and authorization solution for NestJS with JWT, OAuth, OTP, role-based access control, and more
1,654 lines (1,272 loc) โข 89.2 kB
Markdown
<!-- markdownlint-disable MD013 MD024 -->
# Rockets Server Auth
## Project
[](https://www.npmjs.com/package/@bitwild/rockets-auth)
[](https://www.npmjs.com/package/@bitwild/rockets-auth)
[](https://github.com/btwld/rockets)
[](https://github.com/btwld/rockets/graphs/contributors)
[](https://github.com/btwld/rockets/blob/main/LICENSE.txt)
## Table of Contents
- [Introduction](#introduction)
- [Overview](#overview)
- [Key Features](#key-features)
- [Installation](#installation)
- [Tutorial](#tutorial)
- [Quick Start](#quick-start)
- [Basic Setup](#basic-setup)
- [Your First API](#your-first-api)
- [Testing the Setup](#testing-the-setup)
- [How-to Guides](#how-to-guides)
- [Configuration Overview](#configuration-overview)
- [settings](#settings)
- [authentication](#authentication)
- [jwt](#jwt)
- [authJwt](#authjwt)
- [authLocal](#authlocal)
- [authRecovery](#authrecovery)
- [refresh](#refresh)
- [authVerify](#authverify)
- [authRouter](#authrouter)
- [user](#user)
- [password](#password)
- [otp](#otp)
- [email](#email)
- [services](#services)
- [crud](#crud)
- [userCrud](#usercrud)
- [User Management](#user-management)
- [DTO Validation Patterns](#dto-validation-patterns)
- [Entity Customization](#entity-customization)
- [Best Practices](#best-practices)
- [Development Workflow](#development-workflow)
- [DTO Design Patterns](#dto-design-patterns)
- [Explanation](#explanation)
- [Architecture Overview](#architecture-overview)
- [Design Decisions](#design-decisions)
- [Core Concepts](#core-concepts)
---
## Introduction
### Overview
Rockets Server Auth is a comprehensive, enterprise-grade authentication toolkit for building
secure and scalable NestJS applications. It provides a unified solution that
combines authentication, user management, OTP verification, email
notifications, and API documentation into a single, cohesive package.
Built with TypeScript and following NestJS best practices, Rockets Server Auth
eliminates the complexity of setting up authentication systems while
maintaining flexibility for customization and extension.
**Note**: This package provides authentication endpoints and services. For core server functionality, use it together with `@bitwild/rockets-server`.
### Key Features
- **๐ Multiple Authentication Methods**: Password, JWT tokens, refresh tokens, and OAuth
- **๐ OAuth Integration**: Support for Google, GitHub, and Apple OAuth providers
- **๐ฅ User Registration & Management**: Complete signup flow with validation
- **๐ Password Recovery**: Email-based password reset with secure passcodes
- **๐ฑ OTP Support**: One-time password generation and validation for secure authentication
- **๐ Role-Based Access Control**: Admin role system with user role management
- **๐ง Email Notifications**: Built-in email service with template support for OTP and recovery
- **๐ Token Management**: JWT access and refresh token handling with automatic rotation
- **๐ API Documentation**: Automatic Swagger/OpenAPI documentation generation
- **๐ง Highly Configurable**: Extensive configuration options for all authentication modules
- **๐๏ธ Modular Architecture**: Enable/disable specific authentication features as needed
- **๐ก๏ธ Type Safety**: Full TypeScript support with comprehensive interfaces
- **๐งช Testing Support**: Complete testing utilities and fixtures including e2e tests
- **๐ Provider Integration**: JWT auth provider for `@bitwild/rockets-server`
### Installation
**About this package**:
> Rockets Server Auth provides complete authentication and authorization features including login, signup, recovery, OAuth, OTP, and admin functionality. It works together with `@bitwild/rockets-server` to provide a complete authenticated application solution.
**Version Requirements**:
- NestJS: `^10.0.0`
- Node.js: `>=18.0.0`
- TypeScript: `>=4.8.0`
Let's create a new NestJS project:
```bash
npx @nestjs/cli@10 new my-app-with-rockets --package-manager yarn --language TypeScript --strict
```
Install Rockets Server Auth and required dependencies:
```bash
yarn add @bitwild/rockets-server-auth @bitwild/rockets-server \
@concepta/nestjs-typeorm-ext @concepta/nestjs-common \
typeorm @nestjs/typeorm @nestjs/config @nestjs/swagger \
class-transformer class-validator sqlite3
```
---
## Tutorial
### Quick Start
This tutorial will guide you through setting up a complete authentication
system with Rockets Server Auth in just a few steps. We'll use SQLite in-memory
database for instant setup without any configuration.
### Basic Setup
#### Step 1: Create Your Entities
First, create the required database entities by extending the base entities
provided by the SDK. These entities support the complete authentication system:
```typescript
// entities/user.entity.ts
import { Entity, OneToMany } from 'typeorm';
import { UserSqliteEntity } from '@concepta/nestjs-typeorm-ext';
import { UserOtpEntity } from './user-otp.entity';
import { FederatedEntity } from './federated.entity';
@Entity()
export class UserEntity extends UserSqliteEntity {
@OneToMany(() => UserOtpEntity, (userOtp) => userOtp.assignee)
userOtps?: UserOtpEntity[];
@OneToMany(() => FederatedEntity, (federated) => federated.assignee)
federatedAccounts?: FederatedEntity[];
}
```
```typescript
// entities/user-otp.entity.ts
import { Entity, ManyToOne } from 'typeorm';
import { ReferenceIdInterface } from '@concepta/nestjs-common';
import { OtpSqliteEntity } from '@concepta/nestjs-typeorm-ext';
import { UserEntity } from './user.entity';
@Entity()
export class UserOtpEntity extends OtpSqliteEntity {
@ManyToOne(() => UserEntity, (user) => user.userOtps)
assignee!: ReferenceIdInterface;
}
```
```typescript
// entities/federated.entity.ts
import { Entity, ManyToOne } from 'typeorm';
import { ReferenceIdInterface } from '@concepta/nestjs-common';
import { FederatedSqliteEntity } from '@concepta/nestjs-typeorm-ext';
import { UserEntity } from './user.entity';
@Entity()
export class FederatedEntity extends FederatedSqliteEntity {
@ManyToOne(() => UserEntity, (user) => user.federatedAccounts)
assignee!: ReferenceIdInterface;
}
```
#### Step 2: Set Up Environment Variables (Production Only)
For production, create a `.env` file with JWT secrets:
```env
# Required for production
JWT_MODULE_ACCESS_SECRET=your-super-secret-jwt-access-key-here
# Optional - defaults to access secret if not provided
JWT_MODULE_REFRESH_SECRET=your-super-secret-jwt-refresh-key-here
NODE_ENV=development
```
**Note**: In development, JWT secrets are auto-generated if not provided.
#### Step 3: Configure Your Module
Create your main application module with the minimal Rockets SDK setup:
```typescript
// app.module.ts
import { Module } from '@nestjs/common';
import { ConfigModule, ConfigService } from '@nestjs/config';
import { RocketsAuthModule } from '@bitwild/rockets-server-auth';
import { TypeOrmExtModule } from '@concepta/nestjs-typeorm-ext';
import { UserEntity } from './entities/user.entity';
import { UserOtpEntity } from './entities/user-otp.entity';
import { FederatedEntity } from './entities/federated.entity';
@Module({
imports: [
ConfigModule.forRoot({
isGlobal: true,
envFilePath: '.env',
}),
// Database configuration - SQLite in-memory for easy testing
TypeOrmExtModule.forRoot({
type: 'sqlite',
database: ':memory:', // In-memory database - no files created
synchronize: true, // Auto-create tables (dev only)
autoLoadEntities: true,
logging: false, // Set to true to see SQL queries
entities: [UserEntity, UserOtpEntity, FederatedEntity],
}),
// Rockets SDK configuration - minimal setup
RocketsAuthModule.forRootAsync({
imports: [
TypeOrmModule.forFeature([UserEntity]),
TypeOrmExtModule.forFeature({
user: { entity: UserEntity },
role: { entity: RoleEntity },
userRole: { entity: UserRoleEntity },
userOtp: { entity: UserOtpEntity },
federated: { entity: FederatedEntity },
}),
],
inject: [ConfigService],
useFactory: (configService: ConfigService) => ({
// Required services
services: {
mailerService: {
sendMail: (options: any) => {
console.log('๐ง Email would be sent:', {
to: options.to,
subject: options.subject,
// Don't log the full content in examples
});
return Promise.resolve();
},
},
},
// Email and OTP settings
settings: {
email: {
from: 'noreply@yourapp.com',
baseUrl: 'http://localhost:3000',
templates: {
sendOtp: {
fileName: 'otp.template.hbs',
subject: 'Your verification code',
},
},
},
otp: {
assignment: 'userOtp',
category: 'auth-login',
type: 'numeric',
expiresIn: '10m',
},
},
// Optional: Admin and Signup endpoints can be enabled via userCrud extras
}),
}),
],
})
export class AppModule {}
```
#### Step 4: Create Your Main Application
```typescript
// main.ts
import { NestFactory } from '@nestjs/core';
import { ValidationPipe } from '@nestjs/common';
import { SwaggerModule, DocumentBuilder } from '@nestjs/swagger';
import { ExceptionsFilter } from '@concepta/nestjs-common';
import { SwaggerUiService } from '@concepta/nestjs-swagger-ui';
import { AppModule } from './app.module';
async function bootstrap() {
const app = await NestFactory.create(AppModule);
// Enable validation
app.useGlobalPipes(new ValidationPipe());
// get the swagger ui service, and set it up
const swaggerUiService = app.get(SwaggerUiService);
swaggerUiService.builder().addBearerAuth();
swaggerUiService.setup(app);
const exceptionsFilter = app.get(HttpAdapterHost);
app.useGlobalFilters(new ExceptionsFilter(exceptionsFilter));
await app.listen(3000);
console.log('Application is running on: http://localhost:3000');
console.log('API Documentation: http://localhost:3000/api');
console.log('Using SQLite in-memory database (data resets on restart)');
}
bootstrap();
```
### Your First API
With the basic setup complete, your application now provides these endpoints:
#### Authentication Endpoints
- `POST /signup` - Register a new user
- `POST /token/password` - Login with username/password (returns 200 OK with tokens)
- `POST /token/refresh` - Refresh access token
- `POST /recovery/login` - Initiate username recovery
- `POST /recovery/password` - Initiate password reset
- `PATCH /recovery/password` - Reset password with passcode
- `GET /recovery/passcode/:passcode` - Validate recovery passcode
#### OAuth Endpoints
- `GET /oauth/authorize` - Redirect to OAuth provider (Google, GitHub, Apple)
- `GET /oauth/callback` - Handle OAuth callback and return tokens
- `POST /oauth/callback` - Handle OAuth callback via POST method
#### User Profile Endpoints (from @bitwild/rockets-server)
When used together with `@bitwild/rockets-server`, these endpoints are also available:
- `GET /me` - Get current user profile with metadata
- `PATCH /me` - Update current user metadata
#### Admin Endpoints (optional)
If you enable the admin module (see How-to Guides > admin), these routes become
available and are protected by `AdminGuard`:
**User Administration:**
- `GET /admin/users` - List users
- `GET /admin/users/:id` - Get a user
- `POST /admin/users` - Create a user
- `PATCH /admin/users/:id` - Update a user
- `PUT /admin/users/:id` - Replace a user
- `DELETE /admin/users/:id` - Delete a user
**Role Administration:**
- `GET /admin/users/:userId/roles` - List roles assigned to a specific user
- `POST /admin/users/:userId/roles` - Assign role to a specific user
#### OTP Endpoints
- `POST /otp` - Send OTP to user email (returns 200 OK)
- `PATCH /otp` - Confirm OTP code (returns 200 OK with tokens)
**Note**: Rockets Server Auth provides authentication endpoints. For user profile management (`/me` endpoints), use it together with `@bitwild/rockets-server`.
### Testing the Setup
#### 1. Start Your Application
```bash
npm run start:dev
```
#### 2. Register a New User
```bash
curl -X POST http://localhost:3000/signup \
-H "Content-Type: application/json" \
-d '{
"email": "user@example.com",
"password": "SecurePass123",
"username": "testuser"
}'
```
Expected response:
```json
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"email": "user@example.com",
"username": "testuser",
"active": true,
"dateCreated": "2024-01-01T00:00:00.000Z",
"dateUpdated": "2024-01-01T00:00:00.000Z",
"dateDeleted": null,
"version": 1
}
```
#### 3. Login and Get Access Token
```bash
curl -X POST http://localhost:3000/token/password \
-H "Content-Type: application/json" \
-d '{
"username": "testuser",
"password": "SecurePass123"
}'
```
Expected response (200 OK):
```json
{
"accessToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"refreshToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
}
```
**Note**: The login endpoint returns a 200 OK status (not 201 Created) as it's
retrieving tokens, not creating a new resource.
**Defaults Working**: All authentication endpoints work out-of-the-box with
sensible defaults.
#### 4. Access Protected Endpoint
```bash
curl -X GET http://localhost:3000/user \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN_HERE"
```
Expected response:
```json
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"email": "user@example.com",
"username": "testuser",
"active": true,
"dateCreated": "2024-01-01T00:00:00.000Z",
"dateUpdated": "2024-01-01T00:00:00.000Z",
"dateDeleted": null,
"version": 1
}
```
#### 5. Test OTP Functionality
```bash
# Send OTP (returns 200 OK)
curl -X POST http://localhost:3000/otp \
-H "Content-Type: application/json" \
-d '{
"email": "user@example.com"
}'
# Check console for the "email" that would be sent with the OTP code
# Then confirm with the code (replace 123456 with actual code)
# Returns 200 OK with tokens
curl -X PATCH http://localhost:3000/otp \
-H "Content-Type: application/json" \
-d '{
"email": "user@example.com",
"passcode": "123456"
}'
```
Expected OTP confirm response (200 OK):
```json
{
"accessToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"refreshToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
}
```
#### 6. Test OAuth Functionality
```bash
# Redirect to Google OAuth (returns 200 OK)
curl -X GET "http://localhost:3000/oauth/authorize?provider=google&scopes=email,userMetadata"
# Redirect to GitHub OAuth (returns 200 OK)
curl -X GET "http://localhost:3000/oauth/authorize?provider=github&scopes=user,email"
# Redirect to Apple OAuth (returns 200 OK)
curl -X GET "http://localhost:3000/oauth/authorize?provider=apple&scopes=email,name"
# Handle OAuth callback (returns 200 OK with tokens)
curl -X GET "http://localhost:3000/oauth/callback?provider=google"
```
Expected OAuth callback response (200 OK):
```json
{
"accessToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"refreshToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
}
```
๐ **Congratulations!** You now have a fully functional authentication system
with user management, JWT tokens, OAuth integration, and API documentation
running with minimal configuration.
**๐ก Pro Tip**: Since we're using an in-memory database, all data is lost when
you restart the application. This is perfect for testing and development!
### Integrating with @bitwild/rockets-server
Use `RocketsJwtAuthProvider` from this package as the `authProvider` for
`@bitwild/rockets-server` so your app has a global guard that validates
tokens issued by the auth module:
```typescript
// app.module.ts
import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { RocketsAuthModule, RocketsJwtAuthProvider } from '@bitwild/rockets-server-auth';
import { RocketsModule } from '@bitwild/rockets-server';
@Module({
imports: [
TypeOrmModule.forFeature([UserEntity]),
// IMPORTANT: RocketsAuthModule MUST be imported BEFORE RocketsModule
// because RocketsModule depends on RocketsJwtAuthProvider from RocketsAuthModule
RocketsAuthModule.forRootAsync({
imports: [TypeOrmModule.forFeature([UserEntity])],
useFactory: () => ({
services: {
mailerService: { sendMail: async () => Promise.resolve() },
},
}),
}),
// RocketsModule imports AFTER RocketsAuthModule to access RocketsJwtAuthProvider
RocketsModule.forRootAsync({
inject: [RocketsJwtAuthProvider],
useFactory: (authProvider: RocketsJwtAuthProvider) => ({
authProvider,
userMetadata: { createDto: UserMetadataCreateDto, updateDto: UserMetadataUpdateDto },
enableGlobalGuard: true,
}),
}),
],
})
export class AppModule {}
```
### Troubleshooting
#### Common Issues
#### Module Import Order
**Problem**: `Nest can't resolve dependencies of RocketsModule (?). Please make sure that the RocketsJwtAuthProvider is available.`
**Cause**: RocketsModule is imported before RocketsAuthModule
**Solution**: Always import RocketsAuthModule **before** RocketsModule:
```typescript
@Module({
imports: [
RocketsAuthModule.forRootAsync({...}), // โ
First
RocketsModule.forRootAsync({...}), // โ
Second
],
})
```
**Wrong Order** โ:
```typescript
RocketsModule.forRootAsync({...}), // Wrong - first
RocketsAuthModule.forRootAsync({...}), // Wrong - second
```
#### AuthJwtGuard Reflector dependency
If you enable `authJwt.appGuard: true` and see a dependency error regarding
`Reflector`, ensure `Reflector` is available (provided in your module or via
Nest core). The sample app includes `Reflector` in providers.
#### Module Resolution Errors
If you're getting dependency resolution errors:
1. **NestJS Version**: Ensure you're using NestJS `^10.0.0`
2. **Alpha Packages**: All `@concepta/*` packages should use the same alpha
version (e.g., `^7.0.0-alpha.6`)
3. **Clean Installation**: Try deleting `node_modules` and `package-lock.json`,
then run `yarn install`
#### Module Resolution Errors (TypeScript)
If TypeScript can't find modules like `@concepta/nestjs-typeorm-ext`:
```bash
yarn add @concepta/nestjs-typeorm-ext @concepta/nestjs-common \
--save
```
All dependencies listed in the installation section are required and must be
installed explicitly.
---
## How-to Guides
This section provides comprehensive guides for every configuration option
available in the `RocketsAuthOptionsInterface`. Each guide explains what the
option does, how it connects with core modules, when you should customize it
(since defaults are provided), and includes real-world examples.
### Configuration Overview
Rockets Server Auth uses a hierarchical configuration system with the following structure:
```typescript
interface RocketsAuthOptionsInterface {
settings?: RocketsAuthSettingsInterface;
swagger?: SwaggerUiOptionsInterface;
authentication?: AuthenticationOptionsInterface;
jwt?: JwtOptions;
authJwt?: AuthJwtOptionsInterface;
authLocal?: AuthLocalOptionsInterface;
authRecovery?: AuthRecoveryOptionsInterface;
refresh?: AuthRefreshOptions;
authVerify?: AuthVerifyOptionsInterface;
authRouter?: AuthRouterOptionsInterface;
user?: UserOptionsInterface;
password?: PasswordOptionsInterface;
otp?: OtpOptionsInterface;
email?: Partial<EmailOptionsInterface>;
services: {
userModelService?: RocketsAuthUserModelServiceInterface;
notificationService?: RocketsAuthNotificationServiceInterface;
verifyTokenService?: VerifyTokenService;
issueTokenService?: IssueTokenServiceInterface;
validateTokenService?: ValidateTokenServiceInterface;
validateUserService?: AuthLocalValidateUserServiceInterface;
userPasswordService?: UserPasswordServiceInterface;
userPasswordHistoryService?: UserPasswordHistoryServiceInterface;
userAccessQueryService?: CanAccess;
mailerService: EmailServiceInterface; // Required
};
}
```
---
### settings
**What it does**: Global settings that configure the custom OTP and email
services provided by RocketsAuth. These settings are used by the custom OTP
controller and notification services, not by the core authentication modules.
**Core services it connects to**: RocketsAuthOtpService,
RocketsAuthNotificationService
**When to update**: Required when using the custom OTP endpoints
(`POST /otp`, `PATCH /otp`). The defaults use placeholder values that won't
work in real applications.
**Real-world example**: Setting up email configuration for the custom OTP
system:
```typescript
settings: {
email: {
from: 'noreply@mycompany.com',
baseUrl: 'https://app.mycompany.com',
tokenUrlFormatter: (baseUrl, token) =>
`${baseUrl}/auth/verify?token=${token}&utm_source=email`,
templates: {
sendOtp: {
fileName: 'custom-otp.template.hbs',
subject: 'Your {{appName}} verification code - expires in 10 minutes',
},
},
},
otp: {
assignment: 'userOtp',
category: 'auth-login',
type: 'numeric', // Use 6-digit numeric codes instead of UUIDs
expiresIn: '10m', // Shorter expiry for security
},
}
```
---
### authentication
**What it does**: Core authentication module configuration that handles token
verification, validation services and the payload of the token. It provides
three key services:
- **verifyTokenService**: Handles two-step token verification - first
cryptographically verifying JWT tokens using JwtVerifyTokenService, then
optionally validating the decoded payload through a validateTokenService.
Used by authentication guards and protected routes.
- **issueTokenService**: Generates and signs new JWT tokens for authenticated
users. Creates both access and refresh tokens with user payload data and
builds complete authentication responses. Used during login, signup, and
token refresh flows.
- **validateTokenService**: Optional service for custom business logic
validation beyond basic JWT verification. Can check user existence, token
blacklists, account status, or any other custom validation rules.
**Core modules it connects to**: AuthenticationModule (the base authentication
system)
**When to update**: When you need to customize core authentication behavior,
provide custom token services or change how the token payload is structured.
Common scenarios include:
- Implementing custom token verification logic
- Adding business-specific token validation rules
- Modifying token generation and payload structure
- Integrating with external authentication systems
**Real-world example**: Custom authentication configuration:
```typescript
authentication: {
settings: {
enableGuards: true, // Default: true
},
// Optional: Custom services (defaults are provided)
issueTokenService: new CustomTokenIssuanceService(),
verifyTokenService: new CustomTokenVerificationService(),
validateTokenService: new CustomTokenValidationService(),
}
```
**Note**: All token services have working defaults. Only customize if you need
specific business logic.
---
### jwt
**What it does**: JWT token configuration including secrets, expiration times,
and token services.
**Core modules it connects to**: JwtModule, AuthJwtModule, AuthRefreshModule
**When to update**: Only needed if loading JWT settings from a source other than
environment variables (e.g. config files, external services, etc).
**Environment Variables**: The JWT module automatically uses these environment
variables with sensible defaults:
- `JWT_MODULE_DEFAULT_EXPIRES_IN` (default: `'1h'`)
- `JWT_MODULE_ACCESS_EXPIRES_IN` (default: `'1h'`)
- `JWT_MODULE_REFRESH_EXPIRES_IN` (default: `'99y'`)
- `JWT_MODULE_ACCESS_SECRET` (required in production, auto-generated in
development, if not provided)
- `JWT_MODULE_REFRESH_SECRET` (defaults to access secret if not provided)
**Default Behavior**:
- **Development**: JWT secrets are auto-generated if not provided
- **Production**: `JWT_MODULE_ACCESS_SECRET` is required (with
NODE_ENV=production)
- **Token Services**: Default `JwtIssueTokenService` and
`JwtVerifyTokenService` are provided
- **Multiple Token Types**: Separate access and refresh token handling
**Security Notes**:
- Production requires explicit JWT secrets for security
- Development auto-generates secrets for convenience
- Refresh tokens have longer expiration by default
- All token operations are handled automatically
**Real-world example**: Custom JWT configuration (optional - defaults work
for most cases):
```typescript
jwt: {
settings: {
default: {
signOptions: {
issuer: 'mycompany.com',
audience: 'mycompany-api',
},
},
access: {
signOptions: {
issuer: 'mycompany.com',
audience: 'mycompany-api',
},
},
refresh: {
signOptions: {
issuer: 'mycompany.com',
audience: 'mycompany-refresh',
},
},
},
// Optional: Custom services (defaults are provided)
jwtIssueTokenService: new CustomJwtIssueService(),
jwtVerifyTokenService: new CustomJwtVerifyService(),
}
```
**Note**: Environment variables are automatically used for secrets and
expiration times. Only customize `jwt.settings` if you need specific JWT
options like issuer/audience, you can also use the environment variables to
configure the JWT module.
---
### authJwt
**What it does**: JWT-based authentication strategy configuration, including how
tokens are extracted from requests.
**Core modules it connects to**: AuthJwtModule, provides JWT authentication
guards and strategies
**When to update**: When you need custom token extraction logic or want to
modify JWT authentication behavior.
**Real-world example**: Custom token extraction for mobile apps that send tokens
in custom headers:
```typescript
authJwt: {
settings: {
jwtFromRequest: ExtractJwt.fromExtractors([
ExtractJwt.fromAuthHeaderAsBearerToken(), // Standard Bearer token
ExtractJwt.fromHeader('x-api-token'), // Custom header for mobile
(request) => {
// Custom extraction from cookies for web apps
return request.cookies?.access_token;
},
]),
},
// Optional settings (defaults are sensible)
appGuard: true, // Default: true - set true to apply JWT guard globally
// Optional services (defaults are provided)
verifyTokenService: new CustomJwtVerifyService(),
userModelService: new CustomUserLookupService(),
}
```
**Note**: Default token extraction uses standard Bearer token from
Authorization header. Only customize if you need alternative token sources.
---
### authLocal
**What it does**: Local authentication (username/password) configuration and
validation services.
**Core modules it connects to**: AuthLocalModule, handles login endpoint and
credential validation
**When to update**: When you need custom password validation, user lookup logic,
or want to integrate with external authentication systems.
**Real-world example**: Custom local authentication with email login:
```typescript
authLocal: {
settings: {
usernameField: 'email', // Default: 'username'
passwordField: 'password', // Default: 'password'
},
// Optional services (defaults work with TypeORM entities)
validateUserService: new CustomUserValidationService(),
userModelService: new CustomUserModelService(),
issueTokenService: new CustomTokenIssuanceService(),
}
```
**Environment Variables**:
- `AUTH_LOCAL_USERNAME_FIELD` - defaults to `'username'`
- `AUTH_LOCAL_PASSWORD_FIELD` - defaults to `'password'`
**Note**: The default services work automatically with your TypeORM User entity.
Only customize if you need specific validation logic.
---
### authRecovery
**What it does**: Password recovery and account recovery functionality including
email notifications and OTP generation.
**Core modules it connects to**: AuthRecoveryModule, provides password reset
endpoints
**When to update**: When you need custom recovery flows, different notification
methods, or integration with external services.
**Real-world example**: Multi-channel recovery system with SMS and email options:
```typescript
authRecovery: {
settings: {
tokenExpiresIn: '1h', // Recovery token expiration
maxAttempts: 3, // Maximum recovery attempts
},
emailService: new CustomEmailService(),
otpService: new CustomOtpService(),
userModelService: new CustomUserModelService(),
userPasswordService: new CustomPasswordService(),
notificationService: new MultiChannelNotificationService(), // SMS + Email
}
```
---
### refresh
**What it does**: Refresh token configuration for maintaining user sessions
without requiring re-authentication.
**Core modules it connects to**: AuthRefreshModule, provides token refresh
endpoints
**When to update**: When you need custom refresh token behavior, different
expiration strategies, or want to implement token rotation.
**Real-world example**: Secure refresh token rotation for high-security
applications:
```typescript
refresh: {
settings: {
jwtFromRequest: ExtractJwt.fromBodyField('refreshToken'),
tokenRotation: true, // Issue new refresh token on each use
revokeOnUse: true, // Revoke old refresh token
},
verifyTokenService: new SecureRefreshTokenVerifyService(),
issueTokenService: new RotatingTokenIssueService(),
userModelService: new AuditableUserModelService(), // Log refresh attempts
}
```
---
### authVerify
**What it does**: Email verification and account verification functionality.
**Core modules it connects to**: AuthVerifyModule, provides email verification
endpoints
**When to update**: When you need custom verification flows, different
verification methods, or want to integrate with external verification services.
**Real-world example**: Multi-step verification with phone and email:
```typescript
authVerify: {
settings: {
verificationRequired: true, // Require verification before login
verificationExpiresIn: '24h',
},
emailService: new CustomEmailService(),
otpService: new CustomOtpService(),
userModelService: new CustomUserModelService(),
notificationService: new MultiStepVerificationService(), // Email + SMS
}
```
---
### authRouter
**What it does**: OAuth router configuration that handles routing to different
OAuth providers (Google, GitHub, Apple) based on the provider parameter in
the request.
**Core modules it connects to**: AuthRouterModule, provides OAuth routing and
guards
**When to update**: When you need to add or remove OAuth providers, customize
OAuth guard behavior, or modify OAuth routing logic.
**Real-world example**: Custom OAuth configuration with multiple providers:
```typescript
authRouter: {
guards: [
{ name: 'google', guard: AuthGoogleGuard },
{ name: 'github', guard: AuthGithubGuard },
{ name: 'apple', guard: AuthAppleGuard },
// Add custom OAuth providers
{ name: 'custom', guard: CustomOAuthGuard },
],
settings: {
// Custom OAuth router settings
defaultProvider: 'google',
enableProviderValidation: true,
},
}
```
**Default Configuration**: The SDK automatically configures Google, GitHub, and
Apple OAuth providers with sensible defaults.
**OAuth Flow**:
1. Client calls `/oauth/authorize?provider=google&scopes=email userMetadata`
2. AuthRouterGuard routes to the appropriate OAuth guard based on provider
3. OAuth guard redirects to the provider's authorization URL
4. User authenticates with the OAuth provider
5. Provider redirects back to `/oauth/callback?provider=google`
6. AuthRouterGuard processes the callback and returns JWT tokens
---
### user
**What it does**: User management configuration including CRUD operations,
password management, and access control.
**Core modules it connects to**: UserModule, provides user management endpoints
**When to update**: When you need custom user management logic, different access
control, or want to integrate with external user systems.
**Real-world example**: Enterprise user management with role-based access
control:
```typescript
user: {
imports: [
TypeOrmExtModule.forFeature({
user: { entity: UserEntity },
userMetadata: { entity: UserMetadataEntity },
userPasswordHistory: { entity: UserPasswordHistoryEntity },
}),
],
settings: {
enableUserMetadatas: true, // Enable user userMetadatas
enablePasswordHistory: true, // Track password history
},
userModelService: new EnterpriseUserModelService(),
userPasswordService: new SecurePasswordService(),
userAccessQueryService: new RoleBasedAccessService(),
userPasswordHistoryService: new PasswordHistoryService(),
}
```
---
### password
**What it does**: Password policy and validation configuration.
**Core modules it connects to**: PasswordModule, provides password validation
across the system
**When to update**: When you need to enforce specific password policies or
integrate with external password validation services.
**Real-world example**: Enterprise password policy with complexity requirements:
```typescript
password: {
settings: {
minPasswordStrength: 3, // 0-4 scale (default: 2)
maxPasswordAttempts: 5, // Default: 3
requireCurrentToUpdate: true, // Default: false
passwordHistory: 12, // Remember last 12 passwords
},
}
```
**Environment Variables**:
- `PASSWORD_MIN_PASSWORD_STRENGTH` - defaults to `4` if production, `0` if
development (0-4 scale)
- `PASSWORD_MAX_PASSWORD_ATTEMPTS` - defaults to `3`
- `PASSWORD_REQUIRE_CURRENT_TO_UPDATE` - defaults to `false`
**Note**: Password strength is automatically calculated using zxcvbn. History
tracking is optional and requires additional configuration.
---
### otp
**What it does**: One-time password configuration for the OTP system.
**Core modules it connects to**: OtpModule, provides OTP generation and
validation
**When to update**: When you need custom OTP behavior, different OTP types, or
want to integrate with external OTP services.
**Interface**: `OtpSettingsInterface` from `@concepta/nestjs-otp`
```typescript
interface OtpSettingsInterface {
types: Record<string, OtpTypeServiceInterface>;
clearOnCreate: boolean;
keepHistoryDays?: number;
rateSeconds?: number;
rateThreshold?: number;
}
```
**Environment Variables**:
- `OTP_CLEAR_ON_CREATE` - defaults to `false`
- `OTP_KEEP_HISTORY_DAYS` - no default (optional)
- `OTP_RATE_SECONDS` - no default (optional)
- `OTP_RATE_THRESHOLD` - no default (optional)
**Real-world example**: High-security OTP configuration with rate limiting:
```typescript
otp: {
imports: [
TypeOrmExtModule.forFeature({
userOtp: { entity: UserOtpEntity },
}),
],
settings: {
types: {
uuid: {
generator: () => require('uuid').v4(),
validator: (value: string, expected: string) => value === expected,
},
},
clearOnCreate: true, // Clear old OTPs when creating new ones
keepHistoryDays: 30, // Keep OTP history for 30 days
rateSeconds: 60, // Minimum 60 seconds between OTP requests
rateThreshold: 5, // Maximum 5 attempts within rate window
},
}
```
---
### email
**What it does**: Email service configuration for sending notifications and
templates.
**Core modules it connects to**: EmailModule, used by AuthRecoveryModule and
AuthVerifyModule
**When to update**: When you need to use a different email service provider or
customize email sending behavior.
**Interface**: `EmailServiceInterface` from `@concepta/nestjs-email`
**Configuration example**:
```typescript
email: {
service: new YourCustomEmailService(), // Must implement EmailServiceInterface
settings: {}, // Settings object is empty
}
```
---
### services
The `services` object contains injectable services that customize core
functionality. Each service has specific responsibilities:
#### services.userModelService
**What it does**: Core user lookup service used across multiple authentication
modules.
**Core modules it connects to**: AuthJwtModule, AuthRefreshModule,
AuthLocalModule, AuthRecoveryModule
**When to update**: When you need to integrate with external user systems or
implement custom user lookup logic.
**Interface**: `UserModelServiceInterface` from `@concepta/nestjs-user`
**Configuration example**:
```typescript
services: {
userModelService: new YourCustomUserModelService(), // Must implement UserModelServiceInterface
}
```
#### services.notificationService
**What it does**: Handles sending notifications for recovery and verification
processes.
**Core modules it connects to**: AuthRecoveryModule, AuthVerifyModule
**When to update**: When you need custom notification channels (SMS, push
notifications) or integration with external notification services.
**Interface**: `NotificationServiceInterface` from `@concepta/nestjs-authentication`
**Configuration example**:
```typescript
services: {
notificationService: new YourCustomNotificationService(), // Must implement NotificationServiceInterface
}
```
#### services.verifyTokenService
**What it does**: Verifies JWT tokens for authentication.
**Core modules it connects to**: AuthenticationModule, JwtModule
**When to update**: When you need custom token verification logic or integration
with external token validation services.
**Interface**: `VerifyTokenServiceInterface` from `@concepta/nestjs-authentication`
**Configuration example**:
```typescript
services: {
verifyTokenService: new YourCustomVerifyTokenService(), // Must implement VerifyTokenServiceInterface
}
```
#### services.issueTokenService
**What it does**: Issues JWT tokens for authenticated users.
**Core modules it connects to**: AuthenticationModule, AuthLocalModule,
AuthRefreshModule
**When to update**: When you need custom token issuance logic or want to include
additional claims.
**Interface**: `IssueTokenServiceInterface` from `@concepta/nestjs-authentication`
**Configuration example**:
```typescript
services: {
issueTokenService: new YourCustomIssueTokenService(), // Must implement IssueTokenServiceInterface
}
```
#### services.validateTokenService
**What it does**: Validates token structure and claims.
**Core modules it connects to**: AuthenticationModule
**When to update**: When you need custom token validation rules or security
checks.
**Interface**: `ValidateTokenServiceInterface` from `@concepta/nestjs-authentication`
**Configuration example**:
```typescript
services: {
validateTokenService: new YourCustomValidateTokenService(), // Must implement ValidateTokenServiceInterface
}
```
#### services.validateUserService
**What it does**: Validates user credentials during local authentication.
**Core modules it connects to**: AuthLocalModule
**When to update**: When you need custom credential validation or integration
with external authentication systems.
**Interface**: `ValidateUserServiceInterface` from `@concepta/nestjs-authentication`
**Configuration example**:
```typescript
services: {
validateUserService: new YourCustomValidateUserService(), // Must implement ValidateUserServiceInterface
}
```
#### services.userPasswordService
**What it does**: Handles password operations including hashing and validation.
**Core modules it connects to**: UserModule, AuthRecoveryModule
**When to update**: When you need custom password hashing algorithms or password
policy enforcement.
**Interface**: `UserPasswordServiceInterface` from `@concepta/nestjs-user`
**Configuration example**:
```typescript
services: {
userPasswordService: new YourCustomUserPasswordService(), // Must implement UserPasswordServiceInterface
}
```
#### services.userPasswordHistoryService
**What it does**: Manages password history to prevent password reuse.
**Core modules it connects to**: UserModule
**When to update**: When you need to enforce password history policies or custom
password tracking.
**Interface**: `UserPasswordHistoryServiceInterface` from `@concepta/nestjs-user`
**Configuration example**:
```typescript
services: {
userPasswordHistoryService: new YourCustomPasswordHistoryService(), // Must implement UserPasswordHistoryServiceInterface
}
```
#### services.userAccessQueryService
**What it does**: Handles access control and permission queries.
**Core modules it connects to**: UserModule
**When to update**: When you need custom access control logic or integration
with external authorization systems.
**Interface**: `CanAccess` from `@concepta/nestjs-common`
**Configuration example**:
```typescript
services: {
userAccessQueryService: new YourCustomAccessQueryService(), // Must implement CanAccess
}
```
#### services.mailerService (Required)
**What it does**: Core email sending service used throughout the system.
**Core modules it connects to**: EmailModule, AuthRecoveryModule,
AuthVerifyModule, OTP system
**When to update**: Always required. You must provide a working email service
for production.
**Interface**: `EmailServiceInterface` from `@concepta/nestjs-email`
**Configuration example**:
```typescript
services: {
mailerService: new YourCustomMailerService(), // Must implement EmailServiceInterface
}
```
---
### crud
Add a new CRUD endpoint for any entity using `@concepta/nestjs-crud` with
minimal boilerplate. This section provides step-by-step instructions for AI
agents to implement CRUD operations following the v7.0.0-alpha.6 patterns.
**IMPORTANT FOR AI AGENTS**: Follow this exact pattern when implementing
CRUD functionality. The pattern uses `ConfigurableCrudBuilder` plus a
`TypeOrmCrudAdapter` and requires specific imports and structure.
#### Required Imports for CRUD Implementation
**Always import these modules for CRUD:**
```typescript
import { CrudModule } from '@concepta/nestjs-crud'; // For CrudModule.forRoot()
import { TypeOrmModule } from '@nestjs/typeorm'; // For TypeOrmModule.forFeature()
import { TypeOrmCrudAdapter } from '@concepta/nestjs-crud'; // For the adapter pattern
```
**DO NOT use TypeOrmExtModule for CRUD** - this is only for model services.
Use standard TypeOrmModule instead.
#### Module Import Requirements
**Required in your module:**
```typescript
@Module({
imports: [
CrudModule.forRoot({}), // Required for CRUD functionality
TypeOrmModule.forFeature([ProjectEntity]), // Required for repository injection
// NOT TypeOrmExtModule - that's only for model services
],
// ... rest of module
})
```
#### Complete CRUD Implementation Pattern
#### 1) Define your Entity
```typescript
// entities/project.entity.ts
import { Entity, Column, PrimaryGeneratedColumn } from 'typeorm';
@Entity('project')
export class ProjectEntity {
@PrimaryGeneratedColumn('uuid')
id!: string;
@Column()
name!: string;
@Column({ nullable: true })
description?: string;
@Column({ type: 'timestamp', default: () => 'CURRENT_TIMESTAMP' })
createdAt!: Date;
@Column({ type: 'timestamp', default: () => 'CURRENT_TIMESTAMP', onUpdate: 'CURRENT_TIMESTAMP' })
dateUpdated!: Date;
}
```
#### 2) Define your DTOs
```typescript
// dto/project/project.dto.ts
import { ApiProperty } from '@nestjs/swagger';
export class ProjectDto {
@ApiProperty()
id!: string;
@ApiProperty()
name!: string;
@ApiProperty({ required: false })
description?: string;
@ApiProperty()
dateCreated!: Date;
@ApiProperty()
dateUpdated!: Date;
}
// dto/project/project-create.dto.ts
import { ApiProperty } from '@nestjs/swagger';
import { IsNotEmpty, IsOptional, IsString } from 'class-validator';
export class ProjectCreateDto {
@ApiProperty()
@IsString()
@IsNotEmpty()
name!: string;
@ApiProperty({ required: false })
@IsString()
@IsOptional()
description?: string;
}
// dto/project/project-update.dto.ts
import { PartialType } from '@nestjs/swagger';
import { ProjectCreateDto } from './project-create.dto';
export class ProjectUpdateDto extends PartialType(ProjectCreateDto) {}
// dto/project/project-paginated.dto.ts
import { CrudResponsePaginatedDto } from '@concepta/nestjs-crud';
import { ProjectDto } from './project.dto';
export class ProjectPaginatedDto extends CrudResponsePaginatedDto(ProjectDto) {}
```
#### 3) Create a TypeOrmCrudAdapter (REQUIRED PATTERN)
**AI AGENTS: This is the correct adapter pattern for v7.0.0-alpha.6:**
```typescript
// adapters/project-typeorm-crud.adapter.ts
import { Repository } from 'typeorm';
import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { TypeOrmCrudAdapter } from '@concepta/nestjs-crud';
import { ProjectEntity } from '../entities/project.entity';
/**
* Project CRUD Adapter using TypeORM
*
* PATTERN NOTE: This follows the standard pattern where:
* - Extends TypeOrmCrudAdapter<EntityType>
* - Injects Repository<EntityType> via @InjectRepository
* - Calls super(repo) to initialize the adapter
*/
@Injectable()
export class ProjectTypeOrmCrudAdapter extends TypeOrmCrudAdapter<ProjectEntity> {
constructor(
@InjectRepository(ProjectEntity)
repo: Repository<ProjectEntity>,
) {
super(repo);
}
}
```
#### 4) Create a CRUD Builder with build() Method
```typescript
// crud/project-crud.builder.ts
import { ApiTags } from '@nestjs/swagger';
import { ConfigurableCrudBuilder } from '@concepta/nestjs-crud';
import { ProjectEntity } from '../entities/project.entity';
import { ProjectDto } from '../dto/project/project.dto';
import { ProjectCreateDto } from '../dto/project/project-create.dto';
import { ProjectUpdateDto } from '../dto/project/project-update.dto';
import { ProjectPaginatedDto } from '../dto/project/project-paginated.dto';
import { ProjectTypeOrmCrudAdapter } from '../adapters/project-typeorm-crud.adapter';
export const PROJECT_CRUD_SERVICE_TOKEN = Symbol('PROJECT_CRUD_SERVICE_TOKEN');
export class ProjectCrudBuilder extends ConfigurableCrudBuilder<
ProjectEntity,
ProjectCreateDto,
ProjectUpdateDto
> {
constructor() {
super({
service: {
injectionToken: PROJECT_CRUD_SERVICE_TOKEN,
adapter: ProjectTypeOrmCrudAdapter,
},
controller: {
path: 'projects',
model: {
type: ProjectDto,
paginatedType: ProjectPaginatedDto,
},
extraDecorators: [ApiTags('projects')],
},
getMany: {},
getOne: {},
createOne: { dto: ProjectCreateDto },
updateOne: { dto: ProjectUpdateDto },
replaceOne: { dto: ProjectUpdateDto },
deleteOne: {},
});
}
}
```
#### 5) Use build() Method to Get ConfigurableClasses
**AI AGENTS: You must call .build() and extract the classes:**
```typescript
// crud/project-crud.builder.ts (continued)
// Call build() to get the configurable classes
const {
ConfigurableServiceClass,
ConfigurableControllerClass,
} = new ProjectCrudBuilder().build();
// Export the classes that extend the configurable classes
export class ProjectCrudService extends ConfigurableServiceClass {
// Inherits all CRUD operations: getMany, getOne, createOne, updateOne, replaceOne, deleteOne
}
export class ProjectController extends ConfigurableControllerClass {
// Inherits all CRUD endpoints:
// GET /projects (getMany)
// GET /projects/:id (getOne)
// POST /projects (createOne)
// PATCH /projects/:id (updateOne)
// PUT /projects/:id (replaceOne)
// DELETE /projects/:id (deleteOne)
}
```
#### 6) Register in a Module (COMPLETE PATTERN)
**AI AGENTS: This is the exact module pattern you must follow:**
```typescript
// modules/project.module.ts
import { Module } from '@nestjs/common';
import { CrudModule } from '@concepta/nestjs-crud'; // REQUIRED
import { TypeOrmModule } from '@nestjs/typeorm'; // REQUIRED (NOT TypeOrmExtModule)
import { ProjectEntity } from '../entities/project.entity';
import { ProjectTypeOrmCrudAdapter } from '../adapters/project-typeorm-crud.adapter';
import { ProjectController, ProjectServiceProvider } from '../crud/project-crud.builder';
@Module({
imports: [
CrudModule.forRoot({}), // REQUIRED for CRUD functionality
TypeOrmModule.forFeature([ProjectEntity]), // REQUIRED for repository injection
],
providers: [
ProjectTypeOrmCrudAdapter, // The adapter with @Injectable
ProjectServiceProvider, // From the builder.build() result
],
controllers: [
ProjectController, // From the builder.build() result
],
})
export class ProjectModule {}
```
#### 7) Wire up in Main App Module
```typescript
// app.module.ts (add to imports)
@Module({
imports: [
// ... other imports
ProjectModule, // Your new CRUD module
],
})
export class AppModule {}
```
#### Key Patterns for AI Agents
**1. Adapter Pattern**: Always create a `EntityTypeOrmCrudAdapter` that extends
`TypeOrmCrudAdapter<Entity>` (or any other adapter you may need) and injects
`Repository<Entity>`.
**2. Builder Pattern**: Use `ConfigurableCrudBuilder` and call `.build()` to
get `ConfigurableServiceClass` and `ConfigurableControllerClass`.
**3. Module Imports**: Always use:
- `CrudModule.forRoot({})` - for CRUD functionality
- `TypeOrmModule.forFeature([Entity])` - for repository injection
- **NOT** `TypeOrmExtModule` - that's only for model services
**4. Service Token**: Create a unique `Symbol` for each CRUD service token.
**5. DTOs**: Always create separate DTOs for Create, Update, Response, and
Paginated types.
#### Gene