Authentication Flow
This document describes how authentication works across the SoftQuantus platform.
User Authentication (OIDC)
All user-facing applications use OIDC Code Flow with QSA as the identity provider.
sequenceDiagram
autonumber
participant U as User
participant PF as Portal Frontend
participant QSA as QSA (IdP)
participant PB as Portal Backend
U->>PF: Open portal / click login
PF->>QSA: OIDC Authorization Request<br/>(response_type=code)
QSA->>U: Show login page
U->>QSA: Enter credentials
QSA->>U: MFA challenge (if required)
U->>QSA: Complete MFA
QSA->>QSA: Evaluate Conditional Access
QSA-->>PF: Redirect with auth code
PF->>QSA: Exchange code for tokens<br/>(POST /oauth2/token)
QSA-->>PF: access_token + id_token + refresh_token
PF->>PB: API call with Bearer token
PB->>QSA: Fetch JWKS (cached)
PB->>PB: Validate JWT signature<br/>Check iss/aud/exp claims
PB-->>PF: Response + user context
JWT Claims Structure
{
"iss": "https://auth.softquantus.com",
"sub": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
"aud": ["portal-backend", "admin-frontend"],
"exp": 1704369600,
"iat": 1704366000,
"tenant_id": "550e8400-e29b-41d4-a716-446655440000",
"roles": ["admin", "billing_manager"],
"permissions": ["read:customers", "write:contracts"],
"email": "user@example.com",
"name": "John Doe",
"mfa_verified": true
}
M2M Authentication (Service-to-Service)
Backend services use Client Credentials flow for M2M communication.
sequenceDiagram
autonumber
participant PB as Portal Backend
participant QSA as QSA (IdP)
participant QL as QuantumLock
PB->>QSA: POST /oauth2/token<br/>grant_type=client_credentials<br/>client_id=portal-backend<br/>scope=quantumlock:write
QSA->>QSA: Validate client credentials
QSA-->>PB: access_token (service principal)
PB->>QL: API call with Bearer token<br/>X-Service-Principal: portal-backend
QL->>QSA: Fetch JWKS (cached)
QL->>QL: Validate JWT + scopes
QL-->>PB: Response
Token Request (Client Credentials)
POST /oauth2/token HTTP/1.1
Host: auth.softquantus.com
Content-Type: application/x-www-form-urlencoded
grant_type=client_credentials&
client_id=portal-backend&
client_secret=<secret>&
scope=quantumlock:write evidence:sign
Response:
{
"access_token": "eyJhbG...",
"token_type": "Bearer",
"expires_in": 3600,
"scope": "quantumlock:write evidence:sign"
}
Service Principals
| Service | Client ID | Scopes |
|---|---|---|
| Portal Backend | portal-backend | quantumlock:write, evidence:sign |
| Evidence Worker | evidence-worker | evidence:sign, quantumlock:verify |
| Admin Service | admin-service | quantumlock:admin, evidence:admin |
OIDC Discovery
QSA publishes its configuration at the standard discovery endpoint:
GET /.well-known/openid-configuration
{
"issuer": "https://auth.softquantus.com",
"authorization_endpoint": "https://auth.softquantus.com/oauth2/authorize",
"token_endpoint": "https://auth.softquantus.com/oauth2/token",
"jwks_uri": "https://auth.softquantus.com/.well-known/jwks.json",
"userinfo_endpoint": "https://auth.softquantus.com/oauth2/userinfo",
"revocation_endpoint": "https://auth.softquantus.com/oauth2/revoke",
"response_types_supported": ["code", "token", "id_token"],
"grant_types_supported": ["authorization_code", "refresh_token", "client_credentials"],
"scopes_supported": ["openid", "profile", "email", "offline_access"],
"token_endpoint_auth_methods_supported": ["client_secret_basic", "client_secret_post"]
}
Token Validation
Backend services validate tokens by:
- Fetch JWKS from
jwks_uri(with caching) - Verify signature using the appropriate key
- Check claims:
issmatches expected issueraudincludes the serviceexpis in the futureiatis not in the future
- Extract context:
tenant_idfor tenant isolationroles/permissionsfor authorizationsubfor user identification
# Example validation in Portal Backend
from jose import jwt, JWKClient
jwks_client = JWKClient("https://auth.softquantus.com/.well-known/jwks.json")
async def validate_token(token: str) -> dict:
signing_key = jwks_client.get_signing_key_from_jwt(token)
payload = jwt.decode(
token,
signing_key.key,
algorithms=["RS256", "ES256"],
audience="portal-backend",
issuer="https://auth.softquantus.com"
)
return payload
Security Considerations
Token Lifetime
| Token Type | Lifetime | Refresh |
|---|---|---|
| Access Token | 1 hour | Via refresh token |
| Refresh Token | 7 days | Sliding window |
| M2M Token | 1 hour | Request new token |
Required Headers
Authorization: Bearer <access_token>
X-Correlation-Id: <uuid>
X-Tenant-Id: <tenant_id> # Set by backend after auth
Key Rotation
- JWKS keys are rotated every 90 days
- Old keys remain valid for 7 days after rotation
- Services should cache JWKS with TTL of 1 hour