Authentication Flows
Detailed documentation of all authentication flows, including login, passwordless sign-in, workspace switching, and social account linking.
Login (POST /auth/login)
The standard email/password login flow includes several security hardening measures:
- Fetches all users matching the email (multi-tenant support).
- Performs constant-time password comparison (
timingSafeEqual) — prevents timing attacks. - Progressive hash migration — Legacy bcrypt hashes are automatically re-hashed to scrypt on successful login.
- Validates employee status (active, not archived).
- Returns
null(genericUnauthorizedException) if no match — prevents user enumeration. - Generates both access and refresh tokens on success.
warning
The login endpoint never reveals whether an email exists in the system. Failed attempts always return a generic UnauthorizedException.
Workspace Sign-In by Email/Password (POST /auth/signin.email.password)
- Validates email + password against all matching user records.
- Returns workspace list (multi-tenant) instead of direct login.
- User selects a workspace, then signs in with a workspace-scoped JWT.
- Rate limited: 5 requests per 60 seconds.
Workspace Sign-In by Social (POST /auth/signin.email.social)
- Validates the OAuth token against the provider's API (Google, GitHub, Twitter, Facebook).
- Looks up linked social accounts to find matching users.
- Returns workspace list for selection.
- Rate limited: 5 requests per 60 seconds.
Magic Code Sign-In (POST /auth/signin.email → POST /auth/signin.email/confirm)
Magic login codes provide passwordless authentication using cryptographically secure codes:
- Generates a CSPRNG magic code (
crypto.randomInt(), 8-char alphanumeric, 36⁸ ≈ 2.8T combinations). - Sends the code via email.
- User confirms with the code; code is invalidated after first use.
- Configurable expiry via
MAGIC_CODE_EXPIRATION_TIME. - Rate limited: 3 requests per 60 seconds (send), 5 requests per 60 seconds (confirm).
Magic Code Security Properties
crypto.randomInt()(CSPRNG) — notMath.random()- 8-character alphanumeric codes (36⁸ ≈ 2.8 trillion combinations)
- Configurable expiration via
MAGIC_CODE_EXPIRATION_TIME(seconds) - Single-use: Codes are invalidated after first successful verification
- Per-user scoping: Codes are set individually per user record
- Magic codes and links are never logged in server output
Workspace Sign-In by Token (POST /auth/signin.workspace)
- Validates the short-lived workspace JWT.
- Checks user/employee status (active, not archived).
- Generates new access + refresh tokens with full organization context.
- Updates
lastLoginAttimestamp. - Rate limited: 5 requests per 60 seconds.
Social Account Linking (POST /auth/signup.link.account)
- Validates the OAuth token against the provider.
- Links the social account to the authenticated user.
- Rate limited: 3 requests per 60 seconds (stricter).
Workspace Switching (POST /auth/switch-workspace)
- Validates the user has access to the target workspace/tenant.
- Verifies user and employee status in the target context.
- Generates new tokens scoped to the target workspace.
- Authenticated endpoint (requires valid JWT).
Organization Switching (POST /auth/switch-organization)
- Validates the user has an active
UserOrganizationrecord for the target. - Verifies employee status in the target organization.
- Generates new tokens scoped to the target organization.
- Authenticated endpoint (requires valid JWT).
Email Verification
- Verification codes are validated against expiration timestamps.
- Codes are invalidated after successful use (cannot be reused).
- Already-verified emails are rejected with a clear error.
OAuth / Social Login Security
Supported providers: Google, GitHub, Twitter/X, Facebook.
- OAuth tokens are validated server-side against each provider's API before granting access.
- Social accounts are linked to users via a dedicated
SocialAccountService. - Email addresses from OAuth providers are verified before creating or linking accounts.
- The
POST /auth/signup.provider.socialendpoint checks if a user exists by social ID before signup (rate limited: 5/min).
Related Pages
- Token Lifecycle — JWT payload, validation, rotation
- Password Security — hashing, policy, reset flow
- Rate Limiting — per-endpoint limits
- Security Overview — architecture overview
- Social Auth Setup — OAuth provider configuration