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.
On this page
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 inauth.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.tsverify2FA) supportstrustDevice: trueto set a__Host-2fa-trusted-devicecookie (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_sessionscookie, 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 acceptsPUTandPATCH) — Updates profile fields. Passuser_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.timingSafeEqualto 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)
- Initiate Setup:
POST /api/auth/2fa/setup— Generates a TOTP secret and QR code. The encrypted secret is persisted immediately withtwoFactorPending: true. If setup is interrupted (page close, browser crash), re-initiating resumes the existing pending setup. - Verify & Enable:
POST /api/auth/2fa/enable— Verifies the TOTP code with the pending secret and enables 2FA. Payload:{ "code": "123456", "secret": "...", "backupCodes": [...] }. Thesecretfield is optional — if omitted, the stored pending secret is used. On success:twoFactorPendingcleared,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-devicecookie (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.
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:
- Browser sends logout request with OIDC params
- SveltyCMS terminates the local session and clears cookies
- If the OP has an
end_session_endpoint, the browser is redirected there for federated logout - 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_uriis 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/listreturns the full registry of available permissions in the system. - Role Assignment: Managed via
POST /api/auth/update-roles(requiresmanage:system) orPATCH /api/user/{id}(requiresmanage: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
- Request: Client calls
requestMagicLink({ email })remote function - Token Creation: Server creates a single-use
magic_linktoken (15-min TTL) and emails it - Verification:
+page.server.tsload function detectsmagic_tokenquery param, callsverifyMagicLink() - 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
- Token Management (tokens.ts)
- SCIM 2.0 Provisioning (scim.ts)
- Login Security
- Authentication System Architecture