Poll for authorization (query: deviceCode) -- returns status (pending, authorized, expired, denied)
POST
/api/device-code/authorize
Authorize device code (body: userCode, userId)
POST
/api/device-code/deny
Deny device code (body: userCode)
Sessions
Method
Path
Description
GET
/api/sessions/:userId
List active sessions (returns device, IP, location, auth method)
DELETE
/api/sessions/:sessionId
Revoke a session (body: reason?)
DELETE
/api/sessions/user/:userId
Revoke all sessions (body: exceptSessionId?, reason?)
Login Attempts
Method
Path
Description
GET
/api/login-attempts/:userId
List login attempts (query: limit?)
Webhook Events
Event
Description
auth.oauth.linked
OAuth account linked
auth.oauth.unlinked
OAuth account unlinked
auth.passkey.registered
New passkey registered
auth.passkey.used
Passkey authentication succeeded
auth.mfa.enrolled
MFA enrollment completed
auth.mfa.verified
MFA code verified during login
auth.magic_link.sent
Magic link email sent
auth.magic_link.used
Magic link verified
auth.device_code.initiated
Device code flow started
auth.device_code.authorized
Device code authorized by user
auth.device_code.denied
Device code denied
auth.device_code.expired
Device code expired
auth.session.created
New session created
auth.session.revoked
Session revoked (remote logout)
auth.login.success
Successful login (any method)
auth.login.failure
Failed login attempt
auth.login.blocked
Login blocked (rate limit or policy)
Authentication Methods
OAuth
Supports five providers with encrypted token storage. Each provider stores access_token, refresh_token, provider_user_id, profile data, and scopes. Tokens are encrypted at rest using AUTH_ENCRYPTION_KEY.
FIDO2-compatible passwordless authentication. Stores credential public keys with counter values for replay protection. Tracks device type, backup status, and transport methods.
TOTP 2FA
Time-based one-time passwords compatible with Google Authenticator, Authy, and similar apps. Enrollment generates a secret, QR code data URL, and otpauth:// URL. Backup codes provide emergency access if the authenticator device is lost.
Magic Links
Passwordless authentication via email. Tokens are SHA-256 hashed before storage. Supports three purposes: login (sign in), verify (email verification), reset (password reset). Links expire after AUTH_MAGIC_LINK_EXPIRY_SECONDS.
Device Code Flow
For devices without a browser (smart TVs, CLI tools, IoT). The device displays a short userCode and verificationUrl. The user enters the code on a browser-equipped device to authorize. The original device polls GET /api/device-code/poll until authorization completes or the code expires.
Sessions track device, IP, location, and authentication method. The plugin enforces:
Max concurrent sessions: AUTH_SESSION_MAX_PER_USER (default: 10). Oldest sessions are evicted when the limit is exceeded.
Idle timeout: Sessions with no activity for AUTH_SESSION_IDLE_TIMEOUT_HOURS are expired.
Absolute timeout: Sessions older than AUTH_SESSION_ABSOLUTE_TIMEOUT_HOURS are expired regardless of activity.
Use cleanup-expired CLI command or set AUTH_CLEANUP_CRON for automatic expiration.
Troubleshooting
"Encryption key not configured" -- Set AUTH_ENCRYPTION_KEY environment variable. This is required for encrypting OAuth tokens, TOTP secrets, and backup codes.
OAuth provider not listed -- Set the corresponding AUTH_<PROVIDER>_CLIENT_ID and secret. Only configured providers appear in GET /api/oauth/providers.
Passkey registration fails -- Verify AUTH_WEBAUTHN_RP_ID matches your domain and AUTH_WEBAUTHN_ORIGIN matches the page origin exactly (including scheme and port).
TOTP codes rejected -- Check system clock synchronization. TOTP is time-sensitive with a 30-second window. Verify the user completed enrollment verification via POST /api/mfa/totp/verify.
Device code expired before authorization -- Increase AUTH_DEVICE_CODE_EXPIRY_SECONDS. Default is 600 seconds (10 minutes).
Sessions not expiring -- Run cleanup-expired manually or configure AUTH_CLEANUP_CRON. The idle_timeout and absolute_timeout are checked on cleanup, not on every request.