Authentication & Security
OIDC/PKCE authentication, SCIM 2.0 provisioning, RBAC roles, IP allowlists, Fernet encryption, key rotation, and cryptographic audit chain.
OIDC / OAuth 2.0 PKCE
No passwords are stored in the platform database. Authentication uses OpenID Connect with PKCE. The backend validates the RS256 JWT against the IdP's JWKS endpoint — the JWKS is cached per-issuer with configurable TTL. Multiple IdPs (Okta, Azure AD, Auth0, Ping) can be registered via POST /api/v1/idp/configs and the login page automatically renders one SSO button per active config.
Personal Access Tokens
For CI/CD, scripts, and SDK usage. Tokens are stored as hashed values — the plaintext is only shown once at creation time.
curl -X POST /api/v1/auth/tokens \
-H "Authorization: Bearer $OIDC_JWT" \
-d '{ "name": "CI pipeline", "expires_in_days": 90 }'
# Returns { "token": "sk-sovereign-..." } — store immediatelySCIM 2.0 Provisioning
Automated user and group provisioning from your IdP's SCIM connector (RFC 7644). SCIM DELETE is a soft-delete — users are set to status=revoked to preserve audit log foreign key integrity.
| Endpoint | Description |
|---|---|
| `GET /api/scim/v2/Users` | List users (filterable) |
| `POST /api/scim/v2/Users` | Provision a new user |
| `PUT /api/scim/v2/Users/{id}` | Full replace |
| `PATCH /api/scim/v2/Users/{id}` | Partial update |
| `DELETE /api/scim/v2/Users/{id}` | Soft-delete (status → revoked) |
| `GET /api/scim/v2/Groups` | List workspaces as SCIM groups |
Role-Based Access Control
Roles are embedded in JWT claims. Multiple roles per user are supported — passing multiple roles means "any of these roles is sufficient".
| Role | Permissions |
|---|---|
| `admin` | All operations — user management, key rotation, IdP config |
| `ops` | Deploy models, approve HITL, manage clusters, configure IP allowlist |
| `legal` | Approve/reject GitOps manifests and HITL requests, view compliance reports |
| `dev` | Create/read models, run agents, view audit log |
IP Allowlist
Per-workspace CIDR-based access control. Fail-closed: if enabled but empty, all requests are blocked. Health, SCIM, and API docs paths bypass the allowlist. Set TRUST_PROXY=true to derive real IP from X-Forwarded-For behind a load balancer.
1# Enable policy
2curl -X PUT /api/v1/workspaces/{id}/ip-policy -d '{ "enabled": true }'
3
4# Add CIDR
5curl -X POST /api/v1/workspaces/{id}/ip-allowlist \
6 -d '{ "cidr": "10.0.0.0/8", "description": "Corporate VPN" }'Encryption & Key Rotation
Sensitive configuration values (API keys, tool auth configs) are encrypted using Fernet (AES-128-CBC + HMAC-SHA256). The key is resolved at runtime from env, vault, aws_kms, or azure_keyvault. Key rotation: set SECRET_ENCRYPTION_KEY_PREV to the old key, call POST /api/v1/admin/rotate-keys to invalidate the in-process cache, run the re-encryption migration, then remove the _PREV variable.
Cryptographic Audit Chain
Every state-changing operation writes an AuditEntry with SHA-256 hash chaining. Each entry records previous_hash, creating a tamper-evident chain. The audit log has no DELETE or UPDATE endpoint — PostgreSQL row-level security additionally prevents the application role from deleting audit rows.
curl -X POST /api/v1/audit/verify/{entry_id} \
-H "Authorization: Bearer $TOKEN"
# Returns { "valid": true, "chain_length": 847, "genesis_reached": true }