npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@sftech/nestjs-auth-backend

v1.5.0

Published

A standalone, reusable NestJS library for OAuth 2.0 / OIDC authentication with Authorization Code Flow.

Downloads

464

Readme

@sftech/nestjs-auth-backend

A standalone, reusable NestJS library for OAuth 2.0 / OIDC authentication with Authorization Code Flow.

This library provides a complete authentication microservice that can be used as a central auth service for your microservices architecture.

Features

  • OAuth 2.0 / OIDC Authorization Code Flow with PKCE support
  • Database-backed session management using TypeORM
  • Session-based authentication with HTTP-only cookies
  • Token management (Access Token, Refresh Token, ID Token)
  • Single Sign-On (SSO) with provider logout support
  • Dynamic post-login redirect URL with OWASP open-redirect protection (v1.4.0+)
  • Native app deep-link relay for Capacitor / mobile OAuth flows (v1.5.0+)
  • Clean Architecture (domain, application, infrastructure, presentation)
  • REST API endpoints for authentication flows

Installation

npm install @sftech/nestjs-auth-backend

Peer Dependencies

npm install @sftech/nestjs-core @sftech/nestjs-db

Usage

1. Configure Module

import { Module } from '@nestjs/common';
import { NestjsAuthBackendModule } from '@sftech/nestjs-auth-backend';

@Module({
  imports: [
    NestjsAuthBackendModule.register({
      // Module configuration options
    }),
  ],
})
export class AppModule {}

2. Configuration

The module uses configuration values from @sftech/nestjs-core configuration system. Add the following to your app.config.json:

{
  "OAUTH_PROVIDER_URL": "https://your-oauth-provider.com/realms/your-realm",
  "OAUTH_AUTHORIZATION_ENDPOINT": "https://your-oauth-provider.com/realms/your-realm/protocol/openid-connect/auth",
  "OAUTH_TOKEN_ENDPOINT": "https://your-oauth-provider.com/realms/your-realm/protocol/openid-connect/token",
  "OAUTH_USERINFO_ENDPOINT": "https://your-oauth-provider.com/realms/your-realm/protocol/openid-connect/userinfo",
  "OAUTH_END_SESSION_ENDPOINT": "https://your-oauth-provider.com/realms/your-realm/protocol/openid-connect/logout",
  "OAUTH_CLIENT_ID": "your-client-id",
  "OAUTH_CLIENT_SECRET": "your-client-secret",
  "OAUTH_REDIRECT_URL": "http://localhost:3000/api/auth/callback",
  "OAUTH_FRONTEND_CALLBACK_URL": "http://localhost:4200/auth/callback",
  "OAUTH_SCOPE": "openid profile email roles",
  "OAUTH_SESSION_MODE": "single",
  "OAUTH_SESSION_MAX_AGE": "3600000",
  "OAUTH_ALLOWED_REDIRECT_ORIGINS": "https://localhost,http://localhost:4200,https://myapp.example.com",
  "OAUTH_NATIVE_APP_SCHEME": "com.example.myapp"
}

Configuration Parameters

| Parameter | Required | Description | Example | |-----------|----------|-------------|---------| | OAUTH_PROVIDER_URL | Yes | Base URL of OAuth provider | https://keycloak.example.com/realms/myrealm | | OAUTH_AUTHORIZATION_ENDPOINT | Yes | OAuth authorization endpoint | https://keycloak.example.com/realms/myrealm/protocol/openid-connect/auth | | OAUTH_TOKEN_ENDPOINT | Yes | OAuth token endpoint | https://keycloak.example.com/realms/myrealm/protocol/openid-connect/token | | OAUTH_USERINFO_ENDPOINT | Yes | OAuth userinfo endpoint | https://keycloak.example.com/realms/myrealm/protocol/openid-connect/userinfo | | OAUTH_END_SESSION_ENDPOINT | No | OAuth logout endpoint (for SSO logout) | https://keycloak.example.com/realms/myrealm/protocol/openid-connect/logout | | OAUTH_CLIENT_ID | Yes | OAuth client ID | my-app | | OAUTH_CLIENT_SECRET | Yes | OAuth client secret | your-secret-here | | OAUTH_REDIRECT_URL | Yes | OAuth callback URL (this service's own endpoint) | http://localhost:3000/api/auth/callback | | OAUTH_FRONTEND_CALLBACK_URL | No | Default frontend URL to redirect to after login | http://localhost:4200/auth/callback | | OAUTH_SCOPE | Yes | OAuth scopes to request | openid profile email roles | | OAUTH_SESSION_MODE | No | Session mode: single or multi | single (default) | | OAUTH_SESSION_MAX_AGE | No | Session max age in milliseconds | 3600000 (1 hour, default) | | OAUTH_ALLOWED_REDIRECT_ORIGINS | No | Comma-separated list of origins allowed as post-login redirect targets (v1.4.0+) | https://localhost,http://localhost:4200 | | OAUTH_NATIVE_APP_SCHEME | No | Custom URL scheme for native app deep-link relay (v1.5.0+) | com.sftech.ebuilder |

Notes:

  • Session cookie name is fixed to oauth_session (not configurable).
  • When OAUTH_ALLOWED_REDIRECT_ORIGINS is not set, the library derives a single allowed origin from OAUTH_FRONTEND_CALLBACK_URL automatically.
  • When OAUTH_NATIVE_APP_SCHEME is not set, GET /auth/native-relay returns 404.

3. Keycloak Example

For Keycloak, the endpoints follow this pattern:

{
  "OAUTH_PROVIDER_URL": "https://your-keycloak.com/realms/your-realm",
  "OAUTH_AUTHORIZATION_ENDPOINT": "https://your-keycloak.com/realms/your-realm/protocol/openid-connect/auth",
  "OAUTH_TOKEN_ENDPOINT": "https://your-keycloak.com/realms/your-realm/protocol/openid-connect/token",
  "OAUTH_USERINFO_ENDPOINT": "https://your-keycloak.com/realms/your-realm/protocol/openid-connect/userinfo",
  "OAUTH_END_SESSION_ENDPOINT": "https://your-keycloak.com/realms/your-realm/protocol/openid-connect/logout"
}

REST API Endpoints

The module provides the following REST endpoints under /api/auth:

GET /auth/login

Initiates OAuth login flow by redirecting to the OAuth provider.

Query Parameters:

| Parameter | Required | Description | |-----------|----------|-------------| | redirect_url | No | Post-login redirect URL (see validation rules below) |

Successful response: 302 Redirect to OAuth provider authorization endpoint.

Error response: 400 Bad Request when redirect_url is provided but fails validation.

redirect_url Validation Rules (v1.4.0+)

When redirect_url is supplied the library enforces the following rules in order. Any rule failure returns HTTP 400 with a distinct error message — the request is never silently redirected to a fallback.

| Rule | Accepted | Rejected | |------|----------|---------| | Empty / whitespace-only | Treated as absent; falls back to OAUTH_FRONTEND_CALLBACK_URL | — | | Relative path starting with / (not //) | redirect_url=/auth/callback | redirect_url=//evil.com/auth/callback | | Absolute URL — must be parseable | https://localhost/auth/callback | not-a-url | | Absolute URL — origin must be in the allowlist | Origin is in OAUTH_ALLOWED_REDIRECT_ORIGINS | https://evil.com/auth/callback | | Absolute URL — path must be exactly /auth/callback | https://localhost/auth/callback | https://localhost/dashboard | | Absolute URL — must contain no query parameters | https://localhost/auth/callback | https://localhost/auth/callback?foo=bar |

400 error messages:

| Condition | Message | |-----------|---------| | Not a valid URL format | Invalid redirect URL: not a valid URL format | | Origin not in allowlist | Invalid redirect URL: origin not in allowlist | | Path is not /auth/callback | Invalid redirect URL: path must be /auth/callback | | Query parameters present | Invalid redirect URL: must not contain query parameters |

Examples:

# Valid — accepted, user is redirected here after login
GET /auth/login?redirect_url=https%3A%2F%2Flocalhost%2Fauth%2Fcallback

# Valid — Capacitor mobile (https://localhost)
GET /auth/login?redirect_url=https%3A%2F%2Flocalhost%2Fauth%2Fcallback

# Valid — Angular dev server
GET /auth/login?redirect_url=http%3A%2F%2Flocalhost%3A4200%2Fauth%2Fcallback

# Valid — production SPA
GET /auth/login?redirect_url=https%3A%2F%2Fmyapp.example.com%2Fauth%2Fcallback

# Valid — native app relay (relative path, always accepted)
GET /auth/login?redirect_url=%2Fauth%2Fnative-relay

# Invalid — origin not in allowlist → 400
GET /auth/login?redirect_url=https%3A%2F%2Fevil.com%2Fauth%2Fcallback

# Invalid — wrong path → 400
GET /auth/login?redirect_url=https%3A%2F%2Flocalhost%2Fdashboard

# No redirect_url — falls back to OAUTH_FRONTEND_CALLBACK_URL (backward compatible)
GET /auth/login

GET /auth/callback

Handles OAuth callback after user authentication. Exchanges authorization code for tokens and creates a session.

Query Parameters:

  • code (required): Authorization code from OAuth provider
  • state (required): State parameter for CSRF validation

Response: 302 Redirect

  • On success: redirects to the redirect_url that was stored in the PKCE challenge (or OAUTH_FRONTEND_CALLBACK_URL if none was provided during login).
  • On error: redirects to the same target URL with ?error=<code> appended (see Dynamic Error Redirect below).

GET /auth/native-relay (v1.5.0+)

Relay endpoint for native mobile apps (Capacitor, React Native, etc.) completing an OAuth login flow. The native app's in-app browser is redirected here after GET /auth/callback sets the session cookie, and this endpoint performs a final redirect to the app's custom URL scheme so the native runtime can capture the session.

Query Parameters: None.

Cookie: Reads the oauth_session HTTP-only cookie set by GET /auth/callback.

Responses:

| Condition | Status | Location | |-----------|--------|----------| | OAUTH_NATIVE_APP_SCHEME configured, oauth_session cookie present | 302 | {scheme}://auth/callback?session={sessionId} | | OAUTH_NATIVE_APP_SCHEME configured, no oauth_session cookie | 302 | {scheme}://auth/callback?error=no_session | | OAUTH_NATIVE_APP_SCHEME not configured | 404 | — |

Examples:

# Session cookie present — native app receives the session ID
GET /auth/native-relay
Cookie: oauth_session=abc123
→ 302 com.sftech.ebuilder://auth/callback?session=abc123

# No session cookie — native app receives an error signal
GET /auth/native-relay
→ 302 com.sftech.ebuilder://auth/callback?error=no_session

# OAUTH_NATIVE_APP_SCHEME not configured
GET /auth/native-relay
→ 404 Not Found

Notes:

  • The endpoint does not validate whether sessionId corresponds to a live session. Session validity is the responsibility of the native app after it receives the deep link.
  • The sessionId value is URL-encoded before being appended to the redirect URL.
  • Use redirect_url=/auth/native-relay when calling GET /auth/login from a native app (relative paths are always accepted by validateRedirectUrl).

GET /auth/status

Returns current authentication status. Does not require authentication.

Response:

{
  "authenticated": true,
  "userId": "user-id",
  "email": "[email protected]",
  "name": "John Doe",
  "roles": ["admin", "user"],
  "expiresAt": "2024-12-31T23:59:59.000Z",
  "timeRemaining": 3600000
}

GET /auth/user

Returns current user information from session. Requires authentication.

Response:

{
  "sub": "user-id",
  "email": "[email protected]",
  "name": "John Doe",
  "roles": ["admin", "user"],
  "expiresAt": "2024-12-31T23:59:59.000Z",
  "timeRemaining": 3600000
}

POST /auth/refresh

Refreshes access token using refresh token. Extends session lifetime. Requires authentication.

Response:

{
  "message": "Tokens refreshed successfully",
  "expiresAt": "2024-12-31T23:59:59.000Z",
  "timeRemaining": 3600000
}

POST /auth/logout

Ends user session by deleting from database and clearing cookie. If OAUTH_END_SESSION_ENDPOINT is configured, redirects to OAuth provider logout for SSO logout.

Response (without provider logout):

{
  "message": "Logout successful"
}

Response (with provider logout): 302 Redirect to OAuth provider logout endpoint


GET /auth/logout/callback

Handles OAuth provider logout callback. After the OAuth provider completes logout, they redirect back to this endpoint, which then redirects to the frontend.

Response: 302 Redirect to OAUTH_FRONTEND_CALLBACK_URL

Authentication Flow

Login Flow (Web)

  1. Frontend calls GET /auth/login (optionally with redirect_url query parameter)
  2. Backend validates redirect_url if provided (returns 400 on failure — does NOT fall back silently)
  3. Backend generates PKCE challenge and stores the validated redirect_url alongside it
  4. Backend redirects to OAuth provider
  5. User authenticates at OAuth provider
  6. OAuth provider redirects back to GET /auth/callback?code=xxx&state=xxx
  7. Backend exchanges code for tokens (with PKCE verifier)
  8. Backend retrieves the redirect_url stored in the PKCE challenge
  9. Backend creates session in database
  10. Backend sets oauth_session cookie (HTTP-only, SameSite=Lax)
  11. Backend redirects browser to the stored redirect_url (or OAUTH_FRONTEND_CALLBACK_URL if none was stored)
  12. Frontend stores cookie and is now authenticated

Login Flow (Native App — v1.5.0+)

Use this flow when a Capacitor, React Native, or other native app opens an in-app browser to perform OAuth login and needs the session returned via a custom URL scheme deep link.

  1. Native app opens an in-app browser pointed at GET /auth/login?redirect_url=%2Fauth%2Fnative-relay
  2. Backend validates the relative path (always accepted) and stores it in the PKCE challenge
  3. Backend redirects to OAuth provider
  4. User authenticates at OAuth provider
  5. OAuth provider redirects to GET /auth/callback?code=xxx&state=xxx
  6. Backend exchanges code, creates session, sets oauth_session cookie, and redirects to /auth/native-relay
  7. GET /auth/native-relay reads the oauth_session cookie and redirects to {OAUTH_NATIVE_APP_SCHEME}://auth/callback?session={sessionId}
  8. Native app intercepts the deep link, extracts session from query parameters, and stores it for subsequent API calls

Configuration required:

{
  "OAUTH_NATIVE_APP_SCHEME": "com.sftech.ebuilder"
}

Capacitor example (TypeScript):

import { Browser } from '@capacitor/browser';
import { App } from '@capacitor/app';

// 1. Open in-app browser to start OAuth flow
await Browser.open({
  url: 'https://api.example.com/api/auth/login?redirect_url=%2Fauth%2Fnative-relay',
});

// 2. Listen for the deep link returned by /auth/native-relay
App.addListener('appUrlOpen', async (event) => {
  // event.url === 'com.sftech.ebuilder://auth/callback?session=abc123'
  const url = new URL(event.url);
  const sessionId = url.searchParams.get('session');
  const error = url.searchParams.get('error');

  await Browser.close();

  if (error) {
    console.error('Login failed:', error);
    return;
  }

  if (sessionId) {
    // Store sessionId and use it as the oauth_session cookie value
    // in subsequent API requests (e.g. via Capacitor HTTP plugin or Axios)
    await storage.set('sessionId', sessionId);
    router.push('/home');
  }
});

Logout Flow

  1. Frontend calls POST /auth/logout
  2. Backend deletes session from database
  3. Backend clears oauth_session cookie
  4. If OAUTH_END_SESSION_ENDPOINT configured:
    • Backend redirects to OAuth provider logout with id_token_hint
    • OAuth provider clears SSO session
    • OAuth provider redirects back to GET /auth/logout/callback (backend)
    • Backend redirects to OAUTH_FRONTEND_CALLBACK_URL (frontend)
  5. Otherwise: Returns JSON success response

Session Validation

Other microservices can validate sessions by calling GET /auth/status with the session cookie.

See @sftech/nestjs-auth for client library to validate sessions from microservices.

Dynamic Error Redirect (v1.4.0+)

When OAuth callback processing fails (e.g. invalid authorization code, expired state, provider error), the backend must redirect the browser to an error page rather than returning a JSON error body because the response is a browser redirect flow.

Behavior:

  1. If the login was initiated with a redirect_url, that URL is stored in the PKCE challenge alongside the code verifier.
  2. On callback error, the stored redirect_url is retrieved from the thrown exception and used as the redirect target.
  3. The error code is appended as a ?error=<code> query parameter.
  4. If no redirect_url was stored (login was initiated without one), the fallback is OAUTH_FRONTEND_CALLBACK_URL.

Error codes:

| Code | Condition | |------|-----------| | auth_failed | Invalid credentials, expired session, unauthorized | | invalid_request | Missing required parameters (code, state) | | auth_error | Unexpected internal error |

Example redirect on error:

# Login initiated with redirect_url=https://localhost/auth/callback
# Callback fails with invalid code
→ 302 https://localhost/auth/callback?error=auth_failed

# Login initiated without redirect_url
# Callback fails
→ 302 {OAUTH_FRONTEND_CALLBACK_URL}?error=auth_failed

Frontend handling example:

// Angular component at /auth/callback
import { ActivatedRoute } from '@angular/router';

export class AuthCallbackComponent implements OnInit {
  constructor(private route: ActivatedRoute) {}

  ngOnInit(): void {
    const error = this.route.snapshot.queryParamMap.get('error');
    if (error) {
      // Handle error — e.g. show message or redirect to login page
      console.error('Authentication failed:', error);
    }
    // Otherwise: authenticated, proceed to application
  }
}

Open-Redirect Protection (v1.4.0+)

The library enforces OWASP CWE-601 open-redirect protection on all redirect_url values before they are stored. Validation happens at the presentation layer in AuthController.validateRedirectUrl().

Allowlist configuration:

OAUTH_ALLOWED_REDIRECT_ORIGINS accepts a comma-separated list of origins. Each entry can be either a bare origin (https://example.com) or a full URL (the origin is extracted automatically).

{
  "OAUTH_ALLOWED_REDIRECT_ORIGINS": "https://localhost,http://localhost:4200,https://myapp.example.com"
}

Fallback when OAUTH_ALLOWED_REDIRECT_ORIGINS is not set:

The library automatically derives one allowed origin from OAUTH_FRONTEND_CALLBACK_URL. This preserves backward compatibility for deployments with a single frontend origin.

{
  "OAUTH_FRONTEND_CALLBACK_URL": "http://localhost:4200/auth/callback"
  // Derived allowed origin: http://localhost:4200
}

Multi-origin deployment example (Capacitor + dev + prod):

{
  "OAUTH_FRONTEND_CALLBACK_URL": "https://myapp.example.com/auth/callback",
  "OAUTH_ALLOWED_REDIRECT_ORIGINS": "https://localhost,http://localhost:4200,https://myapp.example.com"
}

This configuration permits all three frontends to pass a redirect_url:

  • https://localhost/auth/callback — Capacitor mobile (Ionic/Capacitor uses https://localhost)
  • http://localhost:4200/auth/callback — Angular development server
  • https://myapp.example.com/auth/callback — production SPA

Attack surface covered:

| Attack | Protection | |--------|-----------| | Redirect to unrelated domain (https://evil.com) | Origin must be in allowlist | | Subdomain hijack (https://localhost.evil.com) | Exact origin match, not substring | | Path traversal (https://localhost/admin) | Path must be exactly /auth/callback | | Parameter injection (https://localhost/auth/callback?token=x) | No query parameters allowed | | Protocol-relative redirect (//evil.com/auth/callback) | Must not start with // |

Session Management

Sessions are stored in the database using TypeORM. The session entity includes:

  • sessionId: Unique session identifier (stored in cookie)
  • userId: User ID from OAuth provider
  • accessToken: OAuth access token
  • refreshToken: OAuth refresh token (optional)
  • idToken: OIDC ID token (used for provider logout)
  • expiresAt: Session expiration timestamp
  • userInfo: Cached user information (email, name, roles)

Session Modes

  • Single mode (OAUTH_SESSION_MODE=single): Only one active session per user. New login invalidates previous session.
  • Multi mode (OAUTH_SESSION_MODE=multi): Multiple concurrent sessions allowed per user.

Architecture

This library follows Clean Architecture principles:

lib/
├── domain/                 # Core business models and interfaces
│   ├── models/            # Session, UserInfo, PKCEChallenge domain models
│   ├── repositories/      # Repository interfaces (ports)
│   └── oauth-options.interface.ts
├── application/           # Use cases and business logic
│   └── usecases/          # Login, Callback, Logout, Refresh, etc.
├── infrastructure/        # External concerns
│   ├── entities/         # TypeORM database entities
│   ├── repositories/     # Repository implementations
│   └── mappers/          # Domain ↔ Entity mapping
└── presentation/          # REST API layer
    ├── controllers/      # AuthController
    ├── dtos/            # Request/Response DTOs
    └── guards/          # SessionGuard

Building

nx build nestjs-auth-backend

Publishing

# Build first
nx build nestjs-auth-backend

# Navigate to dist folder
cd dist/libs/nestjs-auth-backend

# Publish to npm
npm publish --access public

Base Classes & Interfaces

IAuthBundle

Interface for the main authentication bundle containing all auth use cases.

Provides:

  • initiateLogin - Start OAuth login flow (accepts optional redirectUrl)
  • handleCallback - Process OAuth callback (returns optional redirectUrl in output)
  • getAuthStatus - Get current auth status
  • getUserInfo - Get current user info
  • refreshToken - Refresh tokens
  • logout - End session
  • createAnonymousSession - Create anonymous session
  • recoverAnonymousSession - Recover anonymous session by recovery code

Usage: This is typically used internally by the module. Access it if you need custom auth flows.


IApiKeyBundle

Interface for API key management bundle.

Provides:

  • createApiKeyUsecase - Create new API key
  • validateApiKeyUsecase - Validate an API key
  • revokeApiKeyUsecase - Revoke an API key
  • listApiKeysUsecase - List all API keys for a user

Usage example:

import { IApiKeyBundle } from '@sftech/nestjs-auth-backend';

@Controller('api-keys')
@UseGuards(JwtAuthGuard)
export class ApiKeyController {
    constructor(
        @Inject('IApiKeyBundle')
        private readonly apiKeyBundle: IApiKeyBundle,
    ) {}

    @Post()
    async create(@Body() dto: CreateApiKeyDto, @CurrentUser() user: UserInfo) {
        return this.apiKeyBundle.createApiKeyUsecase.execute({
            userId: user.sub,
            name: dto.name,
            scopes: dto.scopes,
        });
    }

    @Get()
    async list(@CurrentUser() user: UserInfo) {
        return this.apiKeyBundle.listApiKeysUsecase.execute({ userId: user.sub });
    }

    @Delete(':id')
    async revoke(@Param('id') id: string) {
        return this.apiKeyBundle.revokeApiKeyUsecase.execute({ keyId: id });
    }
}

ISessionRepository

Repository interface for session management.

Methods:

  • create(session: Session): Promise<Session> - Create new session
  • findById(sessionId: string): Promise<Session | null> - Find session by ID
  • findByUserId(userId: string): Promise<Session[]> - Find all sessions for user
  • update(session: Session): Promise<Session> - Update session
  • delete(sessionId: string): Promise<void> - Delete session
  • deleteAllForUser(userId: string): Promise<void> - Delete all sessions for user

Usage: Implement this interface if you need custom session storage (e.g., Redis).


IUserRepository

Repository interface for user management.

Extends: IBaseDbRepository<User>

Additional methods:

  • findByEmail(email: string): Promise<User | null>
  • findByOAuthSub(oauthSub: string): Promise<User | null>

IOAuthOptions

Configuration interface for OAuth settings. Populated automatically from app.config.json by OAuthOptionsMapper.

Properties:

interface IOAuthOptions {
    providerUrl: string;
    authorizationEndpoint: string;
    tokenEndpoint: string;
    userinfoEndpoint: string;
    endSessionEndpoint?: string;
    clientId: string;
    clientSecret: string;
    redirectUri: string;               // OAuth callback URL (this service's own endpoint)
    frontendCallbackUrl?: string;      // Default post-login redirect target
    scope: string;
    sessionMode: 'single' | 'multi';
    sessionMaxAge: number;
    anonymousSessionMaxAge?: number;
    allowedRedirectOrigins?: string[]; // Parsed from OAUTH_ALLOWED_REDIRECT_ORIGINS (v1.4.0+)
    nativeAppScheme?: string;          // Custom URL scheme for native app deep linking (v1.5.0+)
}

allowedRedirectOrigins notes:

  • Populated by splitting OAUTH_ALLOWED_REDIRECT_ORIGINS on commas and trimming whitespace.
  • Each entry is normalized to a bare origin at validation time (e.g. https://example.com/some/path becomes https://example.com).
  • When undefined or empty, the origin of frontendCallbackUrl is used as the single allowed origin.

nativeAppScheme notes (v1.5.0+):

  • Populated from OAUTH_NATIVE_APP_SCHEME in app.config.json.
  • When undefined, GET /auth/native-relay returns 404.
  • The value is used verbatim to build the redirect URL: {nativeAppScheme}://auth/callback?session={sessionId}.

IApiKeyOptions

Configuration interface for API key settings.

Properties:

interface IApiKeyOptions {
    hashAlgorithm: string;    // e.g., 'sha256'
    keyPrefix: string;        // e.g., 'sk_'
    keyLength: number;        // e.g., 32
}

PKCEChallenge

Domain model for PKCE (Proof Key for Code Exchange, RFC 7636) challenges.

Constructor parameters:

  • codeVerifier: string - Random string, 43–128 characters
  • codeChallenge: string - SHA-256 of codeVerifier, base64url-encoded
  • state: string - CSRF protection token, minimum 32 characters
  • createdAt: Date - Creation timestamp (used for 5-minute TTL)
  • redirectUrl?: string - Optional post-login redirect URL stored alongside the challenge (v1.4.0+)

Methods:

  • isValid(): boolean - Returns true if the challenge is less than 5 minutes old
  • isExpired(): boolean - Returns true if the challenge is 5 minutes old or older

Note: PKCE challenges are stored in an in-memory cache (InitiateLoginUseCase.pkceCache) with a 5-minute TTL. When the challenge expires, any stored redirectUrl is also lost; the error redirect falls back to frontendCallbackUrl in that case.


Extending the Module

Custom Session Storage

To use Redis or another storage backend:

import { ISessionRepository } from '@sftech/nestjs-auth-backend';
import { Injectable } from '@nestjs/common';
import { Redis } from 'ioredis';

@Injectable()
export class RedisSessionRepository implements ISessionRepository {
    constructor(private readonly redis: Redis) {}

    async create(session: Session): Promise<Session> {
        await this.redis.setex(
            `session:${session.sessionId}`,
            session.maxAge / 1000,
            JSON.stringify(session),
        );
        return session;
    }

    async findById(sessionId: string): Promise<Session | null> {
        const data = await this.redis.get(`session:${sessionId}`);
        return data ? JSON.parse(data) : null;
    }

    // ... implement other methods
}

// Register in module
@Module({
    providers: [
        {
            provide: 'ISessionRepository',
            useClass: RedisSessionRepository,
        },
    ],
})
export class CustomAuthModule {}

Changelog

See CHANGELOG.md

License

MIT