SSO Setup
SSO Setup
Section titled “SSO Setup”Configure Single Sign-On (SSO) authentication flow in Mantis.
Overview
Section titled “Overview”Mantis implements OIDC Authorization Code flow with PKCE for secure SSO authentication.
Prerequisites
Section titled “Prerequisites”Before configuring SSO:
- Identity provider configured - See OIDC Configuration
- Callback URL configured in IdP
- Mandible external URL configured
Server Configuration
Section titled “Server Configuration”Ensure external_url is configured in Mandible:
[server]external_url = "https://api.mantis.local"Or via environment variable:
MANDIBLE__SERVER__EXTERNAL_URL=https://api.mantis.localAuthentication Flow
Section titled “Authentication Flow”Step 1: Initiate Login
Section titled “Step 1: Initiate Login”The UI requests an authorization URL:
curl -X POST \ -H "Content-Type: application/json" \ -d '{"redirect_url": "https://lens.mantis.local/dashboard"}' \ "https://api.mantis.local/api/v1/auth/oidc/$IDP_SQID/login"Response:
{ "authorization_url": "https://company.okta.com/oauth2/v1/authorize?response_type=code&client_id=xxx&redirect_uri=https://api.mantis.local/api/v1/auth/oidc/callback&scope=openid%20profile%20email&state=abc123&nonce=def456&code_challenge=xyz789&code_challenge_method=S256", "state": "abc123"}Step 2: User Authentication
Section titled “Step 2: User Authentication”The user is redirected to the IdP login page:
- User enters credentials
- IdP authenticates user
- IdP redirects to callback URL with authorization code
Step 3: Token Exchange
Section titled “Step 3: Token Exchange”The callback endpoint processes the response:
# IdP redirects to:GET /api/v1/auth/oidc/callback?code=xxx&state=abc123The API:
- Validates state parameter (CSRF protection)
- Exchanges code for tokens using PKCE verifier
- Validates ID token (signature, claims)
- Creates or updates user
- Returns Mantis JWT tokens
Security Features
Section titled “Security Features”PKCE (Proof Key for Code Exchange)
Section titled “PKCE (Proof Key for Code Exchange)”Prevents authorization code interception:
| Parameter | Value | Purpose |
|---|---|---|
code_challenge_method | S256 | SHA-256 hashing |
code_challenge | Base64URL(SHA256(verifier)) | Sent with authorization request |
code_verifier | Random 43-128 chars | Sent with token request |
State Parameter
Section titled “State Parameter”Prevents CSRF attacks:
Prevents replay attacks:
- Generated for each login attempt
- Included in ID token
- Verified during token validation
- Constant-time comparison prevents timing attacks
Auth State Management
Section titled “Auth State Management”-- Auth state stored in databaseCREATE TABLE oidc_auth_states ( id UUID PRIMARY KEY, state TEXT NOT NULL UNIQUE, nonce TEXT NOT NULL, code_verifier TEXT NOT NULL, provider_id UUID NOT NULL, redirect_url TEXT, created_at TIMESTAMP NOT NULL, expires_at TIMESTAMP NOT NULL, used_at TIMESTAMP);Auth states:
- Expire after 10 minutes (configurable)
- Single-use (consumed on callback)
- Automatically cleaned up
User Provisioning
Section titled “User Provisioning”Auto-Create Users
Section titled “Auto-Create Users”When auto_create_users is enabled:
User Creation Process
Section titled “User Creation Process”-
Extract claims from ID token:
sub- External user IDpreferred_usernameor configured claim - Usernameemailor configured claim - Email address
-
Generate unique username if needed:
alice -> alicealice (exists) -> alice2alice2 (exists) -> alice3 -
Create user record with:
- Random password (unused for SSO)
- Email verified status
- Tenant from provider (if configured)
-
Assign default role (if configured)
-
Create external identity link
External Identity Link
Section titled “External Identity Link”Links Mantis users to IdP identities:
CREATE TABLE external_identities ( id UUID PRIMARY KEY, user_id UUID NOT NULL, provider_id UUID NOT NULL, external_user_id TEXT NOT NULL, external_username TEXT, external_email TEXT, access_token_encrypted TEXT, refresh_token_encrypted TEXT, token_expires_at TIMESTAMP, last_login_at TIMESTAMP, created_at TIMESTAMP NOT NULL, UNIQUE (provider_id, external_user_id));ID Token Validation
Section titled “ID Token Validation”OIDC Core Validation (Section 3.1.3.7)
Section titled “OIDC Core Validation (Section 3.1.3.7)”| Check | Description |
|---|---|
| Signature | Verify using JWKS keys |
iss | Must match issuer URL |
aud | Must contain client_id |
azp | If multiple audiences, must equal client_id |
exp | Token not expired |
iat | Token not too old (5 min max) |
nonce | Must match expected nonce |
at_hash | If present, validates access token binding |
JWKS Caching
Section titled “JWKS Caching”For performance, JWKS keys are cached:
| Setting | Value |
|---|---|
| Cache TTL | 1 hour |
| Refresh interval | 1 minute minimum |
| Refresh trigger | Unknown key ID |
Session Management
Section titled “Session Management”JWT Tokens
Section titled “JWT Tokens”After successful SSO:
{ "access_token": "eyJhbGciOiJFUzI1NiIs...", "token_type": "Bearer", "expires_in": 3600, "user": { "id": "user_abc123", "email": "alice@company.com", "username": "alice", "roles": ["operator"] }}Refresh Token Cookie
Section titled “Refresh Token Cookie”Refresh token is set as HTTP-only cookie:
Set-Cookie: mantis_refresh_token=xxx; HttpOnly; Secure; SameSite=Lax; Path=/; Max-Age=2592000Redirect URL Handling
Section titled “Redirect URL Handling”Post-Login Redirect
Section titled “Post-Login Redirect”Specify where to redirect after login:
curl -X POST \ -H "Content-Type: application/json" \ -d '{"redirect_url": "https://lens.mantis.local/deployments"}' \ "https://api.mantis.local/api/v1/auth/oidc/$IDP_ID/login"Redirect URL Validation
Section titled “Redirect URL Validation”Redirect URLs are validated against an allowlist:
[oidc]allowed_redirect_urls = [ "https://lens.mantis.local", "https://lens.mantis.local/*"]Listing Enabled Providers
Section titled “Listing Enabled Providers”The login page retrieves available SSO providers:
curl "https://api.mantis.local/api/v1/auth/oidc/providers"Response:
[ { "id": "idp_abc123", "name": "Okta", "provider_type": "oidc" }, { "id": "idp_def456", "name": "Azure AD", "provider_type": "oidc" }]Error Handling
Section titled “Error Handling”Common Errors
Section titled “Common Errors”| Error | Cause | Solution |
|---|---|---|
Invalid state | CSRF attempt or expired | Restart login flow |
Nonce mismatch | Replay attack or bug | Restart login flow |
Token expired | ID token too old | Check server clock sync |
Invalid audience | Wrong client_id | Verify IdP configuration |
Provider disabled | IdP not enabled | Enable provider |
IdP Error Response
Section titled “IdP Error Response”IdP may return errors in callback:
GET /callback?error=access_denied&error_description=User%20denied%20accessThese are returned to the client:
{ "error": "IdP returned error: access_denied - User denied access"}Rate Limiting
Section titled “Rate Limiting”SSO endpoints have rate limiting:
| Endpoint | Limit | Window |
|---|---|---|
/auth/oidc/{id}/login | 10 requests | 1 minute |
/auth/oidc/callback | 10 requests | 1 minute |
Configuration:
[rate_limit.auth]enabled = truelogin_attempts_per_minute = 10lockout_duration_secs = 900Audit Logging
Section titled “Audit Logging”SSO events are logged:
{ "event": "auth.sso_login", "category": "authentication", "severity": "security", "actor": { "user_id": 42, "username": "alice" }, "metadata": { "provider_id": 1, "provider_name": "Okta", "external_user_id": "00u1234567890", "created": false }, "outcome": "success"}Troubleshooting
Section titled “Troubleshooting”Login Redirects to Error Page
Section titled “Login Redirects to Error Page”- Check callback URL matches exactly in IdP
- Verify external_url is configured
- Check state parameter validity window
User Not Created
Section titled “User Not Created”- Verify auto_create_users is enabled
- Check email claim is present in ID token
- Verify default role is assigned
Groups Not Synced
Section titled “Groups Not Synced”- Verify groups scope is requested
- Check groups_claim name matches IdP
- Verify role mappings are configured
Token Validation Fails
Section titled “Token Validation Fails”- Check server clock is synchronized
- Verify issuer URL matches exactly
- Check JWKS endpoint is accessible
Next Steps
Section titled “Next Steps”- Role Mappings - Map IdP groups to roles
- External Identities - Manage linked accounts
- OIDC Configuration - Provider setup
