Skip to content

Documentation

Authentication & Identity API Reference

Programmatic API reference for the SveltyCMS identity layer — login, profiles, 2FA, SAML SSO, RBAC permissions, API Keys, Magic Links, and WebAuthn/Passkeys.

7/30/2026
10 min read Edit on GitHub

The Authentication API handles the complete lifecycle of a user identity within SveltyCMS for programmatic access (SDK, mobile apps, external services). It manages everything from standard password-based authentication and Two-Factor Authentication (2FA) to enterprise Single Sign-On (SSO) via SAML 2.0.

Important: The browser-based login flow (/login) now uses type-safe Remote Functions defined in auth.server.ts. These provide full TypeScript inference between components and server logic. The REST API endpoints below remain available for programmatic access (SDK, mobile apps, external services). See Login Security for the page-level authentication documentation.


⚡ Quick Reference

Feature HTTP Endpoint Method Permission Required
Login /api/auth/login POST Public
Logout /api/auth/logout POST Authenticated
OIDC Logout /api/auth/oidc-logout GET, POST Public
Current User /api/auth GET Authenticated
List Users /api/user GET manage:user
Create User /api/auth/create-user POST manage:user
API Keys /api/api-keys GET Authenticated
Create Key /api/api-keys POST Authenticated
Revoke Key /api/api-keys/{id} DELETE Owner or Admin
Magic Link auth.remote.ts (remote fn) POST Public
Passkey Auth auth.remote.ts (remote fn) POST Public
Passkey Reg auth.remote.ts (remote fn) POST Authenticated

| 2FA Status | /api/auth/2fa/status | GET | Authenticated | | 2FA Setup | /api/auth/2fa/setup | POST | Authenticated | | 2FA Enable | /api/auth/2fa/enable | POST | Authenticated | | 2FA Verify | /api/auth/2fa/verify | POST | Authenticated | | 2FA Disable | /api/auth/2fa/disable | POST | Authenticated | | Backup Codes | /api/auth/2fa/backup-codes | GET, POST | Authenticated |

Trusted Devices: The browser-based flow (auth.remote.ts verify2FA) supports trustDevice: true to set a __Host-2fa-trusted-device cookie (30-day TTL, HMAC-SHA256 signed). On subsequent logins from the same device, 2FA is silently skipped.

TOTP Secret Encryption: TOTP secrets are encrypted at rest using AES-256-GCM under the instance’s ENCRYPTION_KEY. Legacy plaintext secrets are handled transparently — no migration needed.

| SAML Login | /api/auth/saml/login | GET | Public | | SAML ACS | /api/auth/saml/acs | POST | Public | | SAML Config | /api/auth/saml/config | POST | manage:system | | Permissions | /api/permission/list | GET | manage:system |


1. Core Authentication

User Lifecycle

Standard authentication uses secure HttpOnly cookies to maintain session state across requests. Session cookies use the __Host- prefix on HTTPS connections per RFC 6265bis.

  • Login: POST /api/auth/login — Validates credentials (email + password), starts a session, sets __Host-auth_sessions cookie, and rotates the CSRF token.
  • Logout: POST /api/auth/logout — Invalidates the current session, clears cookies, and invalidates the session cache.
  • Current User: GET /api/auth — Returns the authenticated user object and their assigned permissions.

Profile Management

Users can update their own security attributes and metadata via dedicated endpoints:

  • Update Attributes: POST /api/auth/update-user-attributes (also accepts PUT and PATCH) — Updates profile fields. Pass user_id: "self" for the current user.
  • Save Avatar: POST /api/auth/save-avatar — Supports both Multipart form-data (file upload) and JSON payloads (URL string).

2. Secure Identity Layer (2FA)

SveltyCMS supports mandatory or optional Two-Factor Authentication via Time-based One-Time Passwords (TOTP).

Security Architecture

  • AES-256-GCM Encryption: TOTP secrets are encrypted at rest using the instance’s ENCRYPTION_KEY. Secrets are never stored in plaintext in the database. Legacy plaintext secrets are handled transparently.
  • TOTP Replay Protection: A consumed-codes registry prevents replay attacks within the 90-second validity window (30s TOTP — 30s clock skew). Fail-closed design — registry errors reject the code.
  • Timing-Safe Comparisons: All code comparisons use crypto.timingSafeEqual to neutralize side-channel attacks.
  • Configurable Window: Set TOTP_WINDOW=2 (env var, default 1) for — 60s tolerance on clock-drifted devices. Max: 5.

2FA Setup Flow (with Pending State)

  1. Initiate Setup: POST /api/auth/2fa/setup — Generates a TOTP secret and QR code. The encrypted secret is persisted immediately with twoFactorPending: true. If setup is interrupted (page close, browser crash), re-initiating resumes the existing pending setup.
  2. Verify & Enable: POST /api/auth/2fa/enable — Verifies the TOTP code with the pending secret and enables 2FA. Payload: { "code": "123456", "secret": "...", "backupCodes": [...] }. The secret field is optional — if omitted, the stored pending secret is used. On success: twoFactorPending cleared, is2FAEnabled: true.

2FA Verification Flow

When 2FA is enabled, a standard login will return a 2FA_REQUIRED status, requiring a second step. Plugins can also force 2FA via the afterAuthenticate hook — see Plugin Architecture.

Endpoint: POST /api/auth/2fa/verify
Payload: { "userId": "...", "code": "123456" }

Trusted Devices (“Remember This Device”)

After successful 2FA verification, the browser flow can pass trustDevice: true:

  • Sets a __Host-2fa-trusted-device cookie (httpOnly, secure, strict, 30-day TTL)
  • Cookie is HMAC-SHA256 signed under the instance’s ENCRYPTION_KEY — forgery-proof
  • Binds to device fingerprint (IP prefix + user-agent hash)
  • On subsequent logins from the same device, 2FA is silently skipped
  • Supports up to 5 trusted devices per user (FIFO eviction)
  • Disabling 2FA clears all trusted devices

Backup Codes

  • Retrieve: GET /api/auth/2fa/backup-codes — Returns backup codes if 2FA is enabled.
  • Regenerate: POST /api/auth/2fa/regenerate-backup-codes — Generates new backup codes.

Disable 2FA

Endpoint: POST /api/auth/2fa/disable
Payload: { "password": "current_password" } — Requires current password verification before disabling.

sequenceDiagram participant User participant Auth as Auth Handler (auth.ts) participant Plugin as Auth Hooks (plugins) participant SDK as Auth Service participant DB as Database User->>Auth: POST /api/auth/login Auth->>Auth: Validate Password (Argon2id) Auth->>Plugin: afterAuthenticate(event) Plugin-->>Auth: deny | requires2FA | pass alt 2FA enabled or plugin-required Auth-->>User: 200 OK (status: 2FA_REQUIRED) User->>Auth: POST /api/auth/2fa/verify (OTP + trustDevice) Auth->>SDK: verifyTOTP(userId, code, fingerprint?) SDK->>DB: Decrypt Secret (AES-256-GCM) SDK-->>Auth: success + trustedDeviceToken? Auth->>Auth: Set __Host-2fa-trusted-device cookie Auth-->>User: 200 OK (Session Started) else trusted device valid Auth->>Auth: Verify __Host-2fa-trusted-device cookie Auth-->>User: 200 OK (2FA skipped) end

3. Enterprise SSO (SAML 2.0)

For enterprise environments, SveltyCMS acts as a Service Provider (SP) and integrates with Identity Providers (IdP) like Okta or Azure AD via the lightweight @node-saml/node-saml library — zero database dependencies.

SAML Configuration

To connect an external IdP, the admin must provide the XML metadata.

Endpoint: POST /api/auth/saml/config Payload: { "tenant": "...", "rawMetadata": "<XML_CONTENT>" }

SAML Assertion Consumer Service

The IdP redirects the user to the ACS endpoint after authentication.

Endpoint: POST /api/auth/saml/acs — Processes the SAML response, validates the assertion, and starts a session.

Just-In-Time (JIT) Provisioning

The system automatically creates user records upon the first successful SAML login if they don’t already exist, mapping IdP attributes to SveltyCMS roles.


4. OIDC SSO (OpenID Connect)

OpenID Connect RP-Initiated Logout enables federated single sign-out across all applications in an OIDC session. When a user logs out of SveltyCMS, the browser is redirected to the OP’s end_session_endpoint to terminate the session at the identity provider as well.

RP-Initiated Logout

Endpoint: GET|POST /api/auth/oidc-logout

Parameters: | Param | Required | Description | | :---- | :------- | :---------- | | id_token_hint | Recommended | The ID Token from the original authentication, used by the OP to identify the session | | post_logout_redirect_uri | Optional | Where to redirect the browser after logout. Must match the provider’s allowlist | | state | Optional | Opaque value for CSRF protection, echoed back by the OP |

Flow:

  1. Browser sends logout request with OIDC params
  2. SveltyCMS terminates the local session and clears cookies
  3. If the OP has an end_session_endpoint, the browser is redirected there for federated logout
  4. On success, the browser lands at post_logout_redirect_uri (if provided and valid)

Provider Configuration: SSO providers are registered via the SSO_PROVIDERS system setting (JSON array of SsoProviderConfig objects). Each provider specifies its issuer, allowedRedirectUris, and optional endSessionEndpoint.

Security:

  • post_logout_redirect_uri is validated against the provider’s allowlist (supports wildcard patterns)
  • Non-SSO sessions (local auth) gracefully fall through to standard logout
  • Provider registry supports multiple OIDC providers simultaneously

See src/databases/auth/sso-session.ts for implementation details.


5. RBAC & Permissions

The authorization system is built on granular permissions assigned to user roles.

  • Check Permissions: GET /api/permission/list returns the full registry of available permissions in the system.
  • Role Assignment: Managed via POST /api/auth/update-roles (requires manage:system) or PATCH /api/user/{id} (requires manage:user).

6. API Keys (Machine-to-Machine)

API Keys enable programmatic access for CI/CD pipelines, external services, and headless clients. Keys use the sck_* prefix and are stored as SHA-256 hashes — plaintext is never persisted.

Key Management

Operation Endpoint Method Description
List Keys /api/api-keys GET Returns all keys for authenticated user (no hash)
Create Key /api/api-keys POST Returns plaintext sck_* key once
Revoke Key /api/api-keys/{id} DELETE Owner or admin only; purges credential cache

Security: Plaintext keys are shown exactly once at creation. After that, only the SHA-256 hash is stored. Revoked keys stop authenticating within 60 seconds (credential cache TTL).

Create Key Request

POST /api/api-keys
{
  "name": "Staging CI",
  "scopes": ["content:read", "media:read"],
  "expiresAt": "2026-12-31T23:59:59Z"
}

Create Key Response

{
  "success": true,
  "data": {
    "_id": "key_abc123",
    "name": "Staging CI",
    "prefix": "sck_a1b2c3d4",
    "key": "sck_a1b2c3d4e5f6...",
    "scopes": ["content:read", "media:read"]
  }
}

6. Magic Links (Passwordless)

Magic Links provide passwordless authentication via email. Implemented as SvelteKit Remote Functions in auth.remote.ts for type-safe client-server communication.

Flow

  1. Request: Client calls requestMagicLink({ email }) remote function
  2. Token Creation: Server creates a single-use magic_link token (15-min TTL) and emails it
  3. Verification: +page.server.ts load function detects magic_token query param, calls verifyMagicLink()
  4. Session: On success, a session is created and the user is redirected

Security Properties

  • Tokens are consumed atomically (TOCTOU-safe consumeToken)
  • Uniform response prevents email enumeration
  • Account lockout is checked before sending
  • Every request and verification is audit-logged

7. WebAuthn / Passkeys

WebAuthn provides phishing-resistant biometric authentication via platform authenticators. Implemented as SvelteKit Remote Functions.

Remote Functions

Function Auth Required Description
getPasskeyAuthOptions No Returns challenge for login
verifyPasskeyAuth No Validates assertion, creates session
getPasskeyRegisterOptions Yes Returns challenge for registration
verifyPasskeyRegister Yes Validates attestation, stores credential

Database

Authenticators are stored as a JSON array on the User record:

interface Authenticator {
  credentialId: string;
  publicKey: JsonWebKey;  // COSE to JWK converted
  counter: number;         // Clone detection
  transports?: string[];   // ["internal", "usb", "nfc", "ble"]
}

8. Guest / Anonymous Auth

Public routes automatically receive an ephemeral ANONYMOUS_USER identity with the guest role. No session is created — access is stateless and read-only.

Permission Granted
content:read
content:write
media:read
media:write
admin:access

Guest identity is assigned by handle-authentication.ts middleware when no valid session or bearer token is present. On subsequent authentication, the guest context is transparently upgraded to the real user session.


Related Documents

apiauth2fasamlsecurityapi-keysmagic-linkswebauthnoidcopenid-connecttrusted-devicestotp-encryption
Was this page helpful?