Authentication
Accountability uses a multi-provider authentication system that allows users to authenticate via multiple methods while maintaining a unified identity.Supported Providers
The system supports five authentication provider types:| Provider | Type | Use Case | Auto-Registration |
|---|---|---|---|
| local | Email/password | Self-service apps | Supported |
| OAuth 2.0 | Consumer apps | Automatic | |
| github | OAuth 2.0 | Developer apps | Automatic |
| workos | SSO | Enterprise apps | Automatic |
| saml | SAML 2.0 | Enterprise apps | Automatic |
Users can link multiple authentication providers to a single account, allowing flexible login options.
Authentication Flows
Local Authentication (Email/Password)
Local Authentication (Email/Password)
Registration
Users register with email and password:Validate password
System validates password against security requirements:
- Minimum 8 characters (configurable)
- Optional uppercase, numbers, special characters
Login
Users authenticate with email and password:Password Storage Security:
- Passwords hashed using argon2id
- Salt automatically generated per password
- Original password never stored or logged
- Generic error messages (“Invalid email or password”) to prevent user enumeration
OAuth Authentication (Google, GitHub)
OAuth Authentication (Google, GitHub)
Authorization Flow
Request authorization URL
Client calls
/api/auth/authorize/:provider to get OAuth URL with CSRF state tokenopenid- OpenID Connectemail- User’s email addressprofile- User’s profile info (name, picture)
- Provider user ID
- Email address (verified)
- Display name
- Profile picture URL (optional)
SSO Authentication (WorkOS, SAML)
SSO Authentication (WorkOS, SAML)
Enterprise SSO Flow
WorkOS Connection Types:
- SAML (Okta, Azure AD, OneLogin)
- OIDC (OpenID Connect)
- Google Workspace
- Microsoft Azure AD
- WorkOS profile ID
- Email address
- First/last name
- Connection ID and type
- Organization ID
- Custom IdP attributes
Session Management
Session Properties
Each session contains:| Property | Description |
|---|---|
| id | Secure random token (session ID) |
| userId | Reference to authenticated user |
| provider | Auth provider used for this session |
| expiresAt | Session expiration timestamp |
| userAgent | Browser/client user agent (audit) |
| createdAt | Session creation timestamp |
Session Duration
Default session durations by provider:| Provider | Duration | Rationale |
|---|---|---|
| local | 7 days | Users expect to stay logged in |
| 24 hours | Consumer OAuth standard | |
| github | 24 hours | Consumer OAuth standard |
| workos | 8 hours | Enterprise workday session |
| saml | 8 hours | Enterprise workday session |
Sessions are configurable via
AUTH_SESSION_DURATION environment variable.Session Security
Token Storage: The session token is set as an httpOnly cookie:- XSS Protection: httpOnly cookies cannot be accessed by JavaScript, preventing token theft even if XSS attacks occur
- Automatic transmission: Browser automatically sends cookies with requests
- CSRF protection: Combined with
sameSite: "strict", cookies are not sent with cross-site requests
- XSS vulnerability: Any XSS attack can read localStorage and exfiltrate tokens
- No expiration control: localStorage has no built-in expiration
- Cross-tab leakage: Malicious scripts in any tab can access localStorage
- Persistence risk: localStorage survives browser restarts
state parameter for CSRF protection:
- Server generates cryptographically random state (32 bytes)
- State included in authorization URL
- State returned in callback
- Server validates state matches before processing
Identity Linking
Users can link multiple authentication providers to a single account:Automatic Linking
WhenAUTH_AUTO_LINK_BY_EMAIL=true (default), authenticating with a new provider automatically links to an existing user with the same verified email.
Email must be verified by the provider for automatic linking to occur.
Manual Linking
Users can explicitly link additional providers:Unlinking
Users can remove linked identities:Domain Models
AuthUser
The main user entity for authentication:packages/core/src/authentication/AuthUser.ts
Session
Authenticated user session:packages/core/src/authentication/Session.ts
UserIdentity
Links users to authentication providers:packages/core/src/authentication/UserIdentity.ts
API Endpoints
Public Endpoints
| Method | Path | Description |
|---|---|---|
| GET | /api/auth/providers | List enabled providers |
| POST | /api/auth/register | Register with local provider |
| POST | /api/auth/login | Login with any provider |
| GET | /api/auth/authorize/:provider | Get OAuth authorization URL |
| GET | /api/auth/callback/:provider | Handle OAuth callback |
Protected Endpoints
| Method | Path | Description |
|---|---|---|
| POST | /api/auth/logout | Invalidate current session |
| GET | /api/auth/me | Get current user with identities |
| POST | /api/auth/refresh | Refresh session token |
| POST | /api/auth/link/:provider | Initiate provider linking |
| GET | /api/auth/link/callback/:provider | Complete provider linking |
| DELETE | /api/auth/identities/:identityId | Unlink provider identity |
Configuration
Environment Variables
Global Settings:Error Handling
Common Errors
| Error | HTTP Status | Cause | Resolution |
|---|---|---|---|
InvalidCredentialsError | 401 | Wrong email/password | Check credentials |
SessionExpiredError | 401 | Session expired | Re-authenticate |
SessionNotFoundError | 401 | Invalid session token | Re-authenticate |
ProviderAuthFailedError | 401 | OAuth/SSO failed | Check provider config |
ProviderNotEnabledError | 404 | Provider not configured | Enable provider |
UserNotFoundError | 404 | User doesn’t exist | Register first |
UserAlreadyExistsError | 409 | Email taken | Use different email |
IdentityAlreadyLinkedError | 409 | Identity linked to other user | Unlink from other account |
PasswordTooWeakError | 400 | Password requirements not met | Use stronger password |
OAuthStateError | 400 | CSRF state mismatch | Restart OAuth flow |
Error Messages
Authentication errors use generic messages to prevent user enumeration:Security Best Practices
Password Security
Password Security
Storage:
- Use argon2id for password hashing
- Automatic salt generation per password
- Never store or log original passwords
- Minimum 12 characters recommended for production
- Require uppercase, numbers, special characters
- Server-side validation only
- Use generic messages for login failures
- Don’t reveal whether email exists
Session Security
Session Security
Token Storage:
- MUST use httpOnly secure cookies
- NEVER use localStorage or sessionStorage
- Set
sameSite: "strict"for CSRF protection
- Use cryptographically secure random bytes
- Minimum 32 bytes (256 bits)
- Base64url encode for transmission
- Set reasonable durations by provider type
- Automatic cleanup of expired sessions
- Manual logout invalidates immediately
OAuth/SAML Security
OAuth/SAML Security
CSRF Protection:
- Always use state parameter
- Generate cryptographically random state
- Validate state on callback
- Exchange authorization code server-side only
- Never expose client secrets to frontend
- Validate all tokens before use
- Only auto-link verified email addresses
- Check provider’s verification status
- Require manual linking for unverified emails
Troubleshooting
Login Issues
Login Issues
“Invalid credentials” for local auth:
- Check user exists in
auth_userstable - Check identity exists in
auth_identitieswithprovider='local' - Verify password hash is set
- Verify redirect URI matches exactly
- Check authorization code hasn’t been used
- Ensure state parameter matches
- Add provider to
AUTH_ENABLED_PROVIDERS - Configure provider credentials
- Restart application
Session Issues
Session Issues
“Session not found”:
- Session was logged out or expired
- Re-authenticate to create new session
- Session duration exceeded
- Configure longer duration or implement refresh
- Check httpOnly cookie is being set
- Verify HTTPS in production
- Check
sameSitecookie attribute
Identity Linking Issues
Identity Linking Issues
“Identity already linked” error:
- Identity is linked to a different user
- Unlink from other account first
- Consider if accounts should be merged
- Verify
AUTH_AUTO_LINK_BY_EMAIL=true - Check email is verified by provider
- Confirm email addresses match exactly
- Users must keep at least one authentication method
- Add another provider before unlinking