Skip to content

Latest commit

 

History

History
611 lines (499 loc) · 17.6 KB

File metadata and controls

611 lines (499 loc) · 17.6 KB
title Authentication Standard
description The standard authentication protocol specification for the ObjectStack ecosystem

ObjectStack Authentication Standard

The standard authentication protocol specification for the ObjectStack ecosystem.

Overview

This document defines the ObjectStack Authentication Standard, a comprehensive, framework-agnostic authentication protocol for ObjectStack applications. This standard supports multiple authentication strategies, session management, and comprehensive security features.

The specification is designed as an interface that can be implemented by any authentication library. better-auth serves as the Reference Implementation (default driver) for this standard.

Implementation Drivers

The authentication standard can be implemented using various drivers:

  • better-auth (default/reference implementation)
  • Auth.js
  • Passport
  • Custom implementations

Features

Authentication Strategies

  • Email/Password: Traditional email and password authentication with customizable password policies
  • Magic Link: Passwordless email-based authentication
  • OAuth: Social login with popular providers (Google, GitHub, Facebook, Twitter, LinkedIn, Microsoft, Apple, Discord, GitLab)
  • Passkey: WebAuthn/FIDO2 biometric authentication
  • OTP: One-time password authentication (SMS, Email)
  • Anonymous: Guest/anonymous session support
  • Enterprise SSO: SAML 2.0, LDAP/Active Directory, and OIDC for enterprise single sign-on

Security Features

  • Rate Limiting: Configurable rate limiting to prevent brute-force attacks
  • CSRF Protection: Built-in CSRF token validation
  • Session Fingerprinting: Enhanced session security with device fingerprinting
  • Two-Factor Authentication (2FA): TOTP-based 2FA with backup codes
  • Account Linking: Link multiple authentication methods to a single user account
  • IP-based Rate Limiting: Prevent attacks from specific IP addresses

Session Management

  • Customizable session expiry and renewal
  • Secure cookie configuration (HttpOnly, Secure, SameSite)
  • Maximum concurrent sessions per user
  • Session update intervals

Developer Features

  • Lifecycle Hooks: beforeSignIn, afterSignIn, beforeSignUp, afterSignUp, beforeSignOut, afterSignOut
  • Database Adapters: Support for Prisma, Drizzle, Kysely, and custom adapters
  • Email Providers: Integration with SendGrid, Mailgun, AWS SES, Resend, SMTP
  • Field Mapping: Map better-auth user fields to your custom user object
  • Plugin System: Extend better-auth with custom plugins

Installation

pnpm add @objectstack/plugin-better-auth

Usage

Basic Example

import type { AuthConfig } from '@objectstack/spec';

const authConfig: AuthConfig = {
  name: 'main_auth',
  label: 'Main Authentication',
  driver: 'better-auth', // Optional, defaults to 'better-auth'
  strategies: ['email_password'],
  baseUrl: 'https://app.example.com',
  secret: process.env.AUTH_SECRET!,
  
  emailPassword: {
    enabled: true,
    requireEmailVerification: true,
    minPasswordLength: 8,
  },
  
  session: {},
  rateLimit: {},
  csrf: {},
  accountLinking: {},
};

OAuth Example

const oauthConfig: AuthConfig = {
  name: 'social_auth',
  label: 'Social Login',
  strategies: ['oauth'],
  baseUrl: 'https://app.example.com',
  secret: process.env.AUTH_SECRET!,
  
  oauth: {
    providers: [
      {
        provider: 'google',
        clientId: process.env.GOOGLE_CLIENT_ID!,
        clientSecret: process.env.GOOGLE_CLIENT_SECRET!,
        scopes: ['openid', 'profile', 'email'],
      },
    ],
  },
  
  session: {},
  rateLimit: {},
  csrf: {},
  accountLinking: {},
};

Multi-Strategy Example

const multiAuthConfig: AuthConfig = {
  name: 'multi_auth',
  label: 'Multi-Strategy Auth',
  strategies: ['email_password', 'oauth', 'magic_link'],
  baseUrl: 'https://app.example.com',
  secret: process.env.AUTH_SECRET!,
  
  emailPassword: {
    enabled: true,
    minPasswordLength: 10,
  },
  
  oauth: {
    providers: [
      { provider: 'google', clientId: '...', clientSecret: '...' },
      { provider: 'github', clientId: '...', clientSecret: '...' },
    ],
  },
  
  magicLink: {
    enabled: true,
    expiryTime: 900,
  },
  
  session: {
    expiresIn: 604800, // 7 days
  },
  
  rateLimit: {
    enabled: true,
    maxAttempts: 5,
  },
  
  csrf: {
    enabled: true,
  },
  
  accountLinking: {
    enabled: true,
    autoLink: false,
  },
};

Enterprise SSO Example

const enterpriseAuthConfig: AuthConfig = {
  name: 'enterprise_sso',
  label: 'Enterprise SSO',
  strategies: ['oauth'],
  baseUrl: 'https://app.example.com',
  secret: process.env.AUTH_SECRET!,
  
  // Standard OAuth for consumer providers
  oauth: {
    providers: [
      { provider: 'google', clientId: '...', clientSecret: '...' },
    ],
  },
  
  // Enterprise authentication methods
  enterprise: {
    // OIDC (Modern standard for enterprise SSO)
    oidc: {
      enabled: true,
      issuer: 'https://auth.company.com',
      clientId: process.env.OIDC_CLIENT_ID!,
      clientSecret: process.env.OIDC_CLIENT_SECRET!,
      scopes: ['openid', 'profile', 'email', 'groups'],
      attributeMapping: {
        email: 'email',
        name: 'name',
        groups: 'roles',
      },
      displayName: 'Login with Corporate SSO',
    },
    
    // SAML 2.0 (Legacy enterprise SSO)
    saml: {
      enabled: true,
      entryPoint: 'https://idp.company.com/saml/sso',
      cert: process.env.SAML_CERT!,
      issuer: 'https://idp.company.com',
      signatureAlgorithm: 'sha256',
      attributeMapping: {
        email: 'http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress',
        name: 'http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name',
      },
      displayName: 'Login with SAML',
    },
    
    // LDAP/Active Directory (On-premise)
    ldap: {
      enabled: true,
      url: 'ldaps://ldap.company.com:636',
      bindDn: 'CN=Service Account,OU=Users,DC=company,DC=com',
      bindCredentials: process.env.LDAP_PASSWORD!,
      searchBase: 'OU=Users,DC=company,DC=com',
      searchFilter: '(&(objectClass=user)(sAMAccountName={{username}}))',
      groupSearchBase: 'OU=Groups,DC=company,DC=com',
      displayName: 'Login with Active Directory',
    },
  },
  
  session: {
    expiresIn: 28800, // 8 hours for enterprise
  },
  
  rateLimit: {
    enabled: true,
    maxAttempts: 5,
  },
  
  csrf: {
    enabled: true,
  },
};

Configuration Reference

Core Configuration

Property Type Required Description
name string Configuration identifier (snake_case)
label string Human-readable label
strategies AuthStrategy[] Enabled authentication strategies
baseUrl string Application base URL
secret string Secret key for signing (min 32 chars)

Strategy Configuration

Email/Password

emailPassword: {
  enabled: boolean;                    // Enable email/password auth
  requireEmailVerification: boolean;   // Require email verification
  minPasswordLength: number;           // Minimum password length (6-128)
  requirePasswordComplexity: boolean;  // Require uppercase, lowercase, numbers, symbols
  allowPasswordReset: boolean;         // Enable password reset
  passwordResetExpiry: number;         // Reset token expiry in seconds
}

Magic Link

magicLink: {
  enabled: boolean;           // Enable magic link auth
  expiryTime: number;         // Link expiry in seconds (default: 900)
  sendEmail?: Function;       // Custom email sending function
}

Passkey (WebAuthn)

passkey: {
  enabled: boolean;                              // Enable passkey auth
  rpName: string;                                // Relying Party name
  rpId?: string;                                 // Relying Party ID (defaults to domain)
  allowedOrigins?: string[];                     // Allowed origins
  userVerification?: 'required' | 'preferred' | 'discouraged';
  attestation?: 'none' | 'indirect' | 'direct' | 'enterprise';
}

OAuth

oauth: {
  providers: [{
    provider: 'google' | 'github' | 'facebook' | ...; // OAuth provider
    clientId: string;                                  // OAuth client ID
    clientSecret: string;                              // OAuth client secret
    scopes?: string[];                                 // Requested scopes
    redirectUri?: string;                              // Callback URL
    enabled?: boolean;                                 // Enable/disable provider
    displayName?: string;                              // Button label
    icon?: string;                                     // Icon URL
  }]
}

Session Configuration

session: {
  expiresIn: number;                         // Session expiry in seconds (default: 604800)
  updateAge: number;                         // Update interval in seconds (default: 86400)
  cookieName: string;                        // Cookie name
  cookieSecure: boolean;                     // Use secure cookies (HTTPS only)
  cookieSameSite: 'strict' | 'lax' | 'none'; // SameSite attribute
  cookieDomain?: string;                     // Cookie domain
  cookiePath: string;                        // Cookie path (default: '/')
  cookieHttpOnly: boolean;                   // HttpOnly attribute
}

Security Configuration

rateLimit: {
  enabled: boolean;               // Enable rate limiting
  maxAttempts: number;            // Max login attempts (default: 5)
  windowMs: number;               // Time window in ms (default: 900000)
  blockDuration: number;          // Block duration in ms
  skipSuccessfulRequests: boolean; // Only count failed requests
}

csrf: {
  enabled: boolean;      // Enable CSRF protection
  tokenLength: number;   // CSRF token length (default: 32)
  cookieName: string;    // CSRF cookie name
  headerName: string;    // CSRF header name
}

security: {
  allowedOrigins?: string[];      // CORS allowed origins
  trustProxy: boolean;            // Trust proxy headers
  ipRateLimiting: boolean;        // Enable IP-based rate limiting
  sessionFingerprinting: boolean; // Enable session fingerprinting
  maxSessions: number;            // Max concurrent sessions (default: 5)
}

Two-Factor Authentication

twoFactor: {
  enabled: boolean;           // Enable 2FA
  issuer?: string;            // TOTP issuer name
  qrCodeSize: number;         // QR code size in pixels (default: 200)
  backupCodes?: {
    enabled: boolean;         // Enable backup codes
    count: number;            // Number of backup codes (default: 10)
  }
}

Enterprise Authentication

enterprise: {
  // OpenID Connect (Modern enterprise SSO)
  oidc?: {
    enabled: boolean;                // Enable OIDC
    issuer: string;                  // OIDC Issuer URL
    clientId: string;                // OIDC client ID
    clientSecret: string;            // OIDC client secret
    scopes?: string[];               // OIDC scopes (default: ['openid', 'profile', 'email'])
    attributeMapping?: Record<string, string>; // Map IdP claims to user fields
    displayName?: string;            // Button label
    icon?: string;                   // Icon URL
  },
  
  // SAML 2.0 (Legacy enterprise SSO)
  saml?: {
    enabled: boolean;                // Enable SAML
    entryPoint: string;              // IdP SSO URL
    cert: string;                    // IdP Public Certificate (PEM)
    issuer: string;                  // Entity ID of the IdP
    signatureAlgorithm?: 'sha256' | 'sha512'; // Signature algorithm
    attributeMapping?: Record<string, string>; // Map SAML attributes to user fields
    displayName?: string;            // Button label
    icon?: string;                   // Icon URL
  },
  
  // LDAP/Active Directory (On-premise)
  ldap?: {
    enabled: boolean;                // Enable LDAP
    url: string;                     // LDAP Server URL (ldap:// or ldaps://)
    bindDn: string;                  // Bind DN
    bindCredentials: string;         // Bind credentials
    searchBase: string;              // Search base DN
    searchFilter: string;            // Search filter
    groupSearchBase?: string;        // Group search base DN
    displayName?: string;            // Button label
    icon?: string;                   // Icon URL
  }
}

Lifecycle Hooks

hooks: {
  beforeSignIn?: ({ email }) => Promise<void>;
  afterSignIn?: ({ user, session }) => Promise<void>;
  beforeSignUp?: ({ email, name? }) => Promise<void>;
  afterSignUp?: ({ user }) => Promise<void>;
  beforeSignOut?: ({ sessionId }) => Promise<void>;
  afterSignOut?: ({ sessionId }) => Promise<void>;
}

Database Field Mapping

The mapping configuration allows you to map ObjectStack standard field names (which follow Auth.js conventions) to driver-specific field names. This is particularly useful for ensuring compatibility with authentication libraries like better-auth that use different column naming conventions.

mapping: {
  // User model field mapping (optional)
  user?: {
    emailVerified: 'email_verified',  // Map to snake_case
    createdAt: 'created_at',
    updatedAt: 'updated_at',
  },
  
  // Session model field mapping (default better-auth compatible)
  session: {
    sessionToken: 'token',            // better-auth uses 'token'
    expires: 'expiresAt',             // better-auth uses 'expiresAt'
  },
  
  // Account model field mapping (default better-auth compatible)
  account: {
    providerAccountId: 'accountId',   // better-auth uses 'accountId'
    provider: 'providerId',           // better-auth uses 'providerId'
  },
  
  // Verification token field mapping (optional)
  verificationToken?: {
    identifier: 'email',
  },
}

Default Mappings for better-auth Compatibility:

By default, the session and account mappings are pre-configured for better-auth compatibility:

ObjectStack Field better-auth Field
sessionToken token
expires expiresAt
providerAccountId accountId
provider providerId

You only need to specify the mapping configuration if you want to:

  • Use a different authentication driver with non-standard field names
  • Override the default better-auth mappings
  • Add custom mappings for user or verification token fields

Example with custom mappings:

const authConfig: AuthConfig = {
  name: 'custom_auth',
  label: 'Custom Auth',
  driver: 'custom-driver',
  strategies: ['email_password'],
  baseUrl: 'https://example.com',
  secret: process.env.AUTH_SECRET!,
  
  mapping: {
    user: {
      emailVerified: 'is_verified',
      createdAt: 'created',
      updatedAt: 'modified',
    },
    session: {
      sessionToken: 'session_id',
      expires: 'expires_at',
    },
    account: {
      providerAccountId: 'external_id',
      provider: 'auth_provider',
    },
  },
  
  session: {},
  rateLimit: {},
  csrf: {},
  accountLinking: {},
};

Supported OAuth Providers

  • Google (google)
  • GitHub (github)
  • Facebook (facebook)
  • Twitter (twitter)
  • LinkedIn (linkedin)
  • Microsoft (microsoft)
  • Apple (apple)
  • Discord (discord)
  • GitLab (gitlab)
  • Custom OAuth2 (custom)

Database Adapters

  • Prisma (prisma)
  • Drizzle (drizzle)
  • Kysely (kysely)
  • Custom (custom)

Email Providers

  • SMTP (smtp)
  • SendGrid (sendgrid)
  • Mailgun (mailgun)
  • AWS SES (ses)
  • Resend (resend)
  • Custom (custom)

Examples

See examples/auth-better-examples.ts for comprehensive usage examples including:

  • Basic email/password authentication
  • OAuth with Google and GitHub
  • Multi-strategy authentication
  • Production-ready configuration
  • Plugin manifest integration

Schema Files

The authentication system is organized into three main files:

  1. Configuration (packages/spec/src/system/auth.zod.ts): Defines how to login - OAuth, Email, SAML, LDAP, better-auth driver settings
  2. Data Models (packages/spec/src/system/identity.zod.ts): Defines who is logged in - User, Session, Account schemas
  3. Wire Protocol (packages/spec/src/system/auth-protocol.ts): Defines how to communicate - API constants, headers, error codes

Additional files:

  • Tests: packages/spec/src/system/auth.test.ts
  • JSON Schema: packages/spec/json-schema/AuthConfig.json
  • Documentation: content/docs/references/system/AuthConfig.mdx

Type Safety

All schemas are defined using Zod and TypeScript types are inferred automatically:

// Authentication configuration types
import type {
  AuthConfig,
  StandardAuthProvider,
  AuthStrategy,
  OAuthProvider,
  SessionConfig,
  EnterpriseAuthConfig,
  OIDCConfig,
  SAMLConfig,
  LDAPConfig,
  // ... and more
} from '@objectstack/spec';

// User and session data model types
import type {
  User,
  Account,
  Session,
  VerificationToken,
} from '@objectstack/spec';

// Wire protocol types
import type {
  AuthHeaders,
  AuthResponse,
  AuthError,
  TokenPayload,
} from '@objectstack/spec';

import { AUTH_CONSTANTS, AUTH_ERROR_CODES } from '@objectstack/spec';

Naming Conventions

Following ObjectStack conventions:

  • Configuration Keys (TypeScript properties): camelCase (e.g., maxAttempts, emailPassword)
  • Machine Names (Data values): snake_case (e.g., name: 'main_auth', strategy: 'email_password')

Resources

License

Apache 2.0