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.6.0

Published

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

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+)
  • 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"
}

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_ROLE_CLAIM_PATH | Required for /api-keys | Dot-separated path into the OAuth userinfo response or its additionalClaims where the caller's role list lives (v1.6.0+) | realm_access.roles (Keycloak) or roles | | OAUTH_ADMIN_ROLES | Required for /api-keys | Comma-separated list of role identifiers that grant administrative access to API key management endpoints (v1.6.0+) | admin,api-key-manager |

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_ROLE_CLAIM_PATH and OAUTH_ADMIN_ROLES are unset, all /api-keys management endpoints return HTTP 503 — fail-closed (v1.6.0+).

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"
}

Authentication and Authorization Model (v1.6.0+)

Security advisory@sftech/[email protected] shipped the ApiKeyController without any authentication guard. Any unauthenticated caller could enumerate, create, rotate, or revoke API keys. All <= 1.5.0 versions are vulnerable; upgrade to 1.6.0. If you cannot upgrade immediately, block /api-keys at the reverse-proxy edge (see "Interim mitigation" below).

Per-route policy

| Route | Authentication | Authorization | Rate limit | |---|---|---|---| | GET /auth/login | public | — | — | | GET /auth/callback | public | — | — | | GET /auth/status | public | — | — | | GET /auth/user | session | — | — | | POST /auth/refresh | session | — | — | | POST /auth/logout | session | — | — | | POST /auth/anonymous | public | — | per-IP (10 req / 60 s) | | POST /auth/anonymous/recover | public | — | per-IP (10 req / 60 s) | | GET /api-keys | session | admin role required | — | | GET /api-keys/:id | session | admin role required | — | | POST /api-keys | session | admin role required | — | | POST /api-keys/:id/rotate | session | admin role required | — | | DELETE /api-keys/:id | session | admin role required | — | | POST /api-keys/validate | public (@Public()) | — | per-IP (60 req / 60 s) |

Configuring admin role enforcement

API key management endpoints require BOTH a valid session AND that the caller holds one of the configured admin roles. Without configuration, those endpoints fail closed with HTTP 503.

{
  "OAUTH_ROLE_CLAIM_PATH": "realm_access.roles",
  "OAUTH_ADMIN_ROLES": "admin,api-key-manager"
}
  • OAUTH_ROLE_CLAIM_PATH is a dot-separated path resolved against the OAuth userinfo response. The library reads from the standard fields and from additionalClaims. Use realm_access.roles for Keycloak; roles for providers that emit a top-level array; https://example.com/roles (with the dots quoted in your config layer if necessary) for custom namespaced claims.
  • OAUTH_ADMIN_ROLES is a comma-separated list. A caller passes the admin check if any of their resolved roles appears in this list.
  • The library tolerates two claim shapes: a string array (["admin", "user"]) or a comma-separated string ("admin,user"). Any other shape (object, number, missing) is treated as "no roles" — never as "any role".
  • If the consuming service starts without these keys configured, the startup log prints a WARN line; calls to management endpoints respond with HTTP 503 and a clear error message.

The validate endpoint

POST /api-keys/validate is the only /api-keys route that does not require a session. It is intended for backend-to-backend traffic that authenticates inbound requests using an API key. To prevent brute-force enumeration of the key space, the library applies a per-source-IP rate limiter (default 60 requests / 60 seconds, in-memory fixed window) before any database lookup. When the budget is exceeded, the response is HTTP 429 with a retryAfter value.

Upgrading from 1.5.0

  1. Upgrade the package: pnpm up @sftech/[email protected].
  2. Add the two new configuration keys (OAUTH_ROLE_CLAIM_PATH, OAUTH_ADMIN_ROLES) to your config layer.
  3. Verify that your OAuth provider includes the role claim in userinfo. For Keycloak, the realm_access.roles claim is included by default for confidential clients with the view-roles scope.
  4. Sanity-check after deploy:
    • curl -i https://your-host/api/api-keys should return HTTP 401 (no session).
    • curl -i --cookie "oauth_session=<valid>" https://your-host/api/api-keys returns HTTP 403 if the session user has no admin role, HTTP 200 if they do.
    • If you forgot to set the env keys, you will see HTTP 503 with the message "Admin role enforcement is not configured".

Interim mitigation (if you cannot upgrade immediately from 1.5.0)

location /api/api-keys {
    return 404;
}

Reload nginx. This is no-functional-loss as long as the consuming service does not call /api-keys from external traffic. Remove the block once you have upgraded to 1.6.0 and configured the admin role keys.

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

# 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/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

  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

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+)
}

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.

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