SAML SSO & SCIM provisioning
AuditTrail supports enterprise identity integration at the organization
level: SAML 2.0 single sign-on so members log in through your IdP, and SCIM 2.0
provisioning so user lifecycle (create / read / deactivate) is driven by your
directory. Both are configured per organization and gated by the org RBAC roles
(owner > admin > annotator > viewer).
SAML SSO
You register your identity provider's metadata once per org, then your IdP
POSTs signed assertions to AuditTrail's Assertion Consumer Service (ACS), which
provisions/refreshes the User + OrgMember rows and sets the session cookie.
The config is stored in the saml_configs table and carries the IdP entity ID,
SSO URL, X.509 signing certificate, your SP entity ID, a default_role for
newly-provisioned members (admin / annotator / viewer), and an enabled
flag.
REST surface
| Method | Path | Role | Purpose |
|---|---|---|---|
POST | /api/v1/saml/config/{org_id} | owner | Create or update the org's SAML config |
GET | /api/v1/saml/config/{org_id} | admin+ | Read the current config |
POST | /api/v1/saml/acs/{org_slug} | signed assertion | Assertion Consumer Service |
The ACS endpoint takes a standard form POST (SAMLResponse, optional
RelayState). AuditTrail validates the assertion signature against the stored
IdP cert and audience, upserts the user by email, ensures org membership at the
configured default_role, sets the session cookie, and 302-redirects to
RelayState (or /overview). An assertion with no email, or one that fails
signature/audience checks, is rejected (400/401).
# Point your IdP's ACS URL at:
https://auditrail.yourco.com/api/v1/saml/acs/<your-org-slug>SCIM 2.0 provisioning
SCIM lets your IdP push user lifecycle into AuditTrail. You mint a SCIM bearer
token scoped to one org, configure it in your IdP, and the IdP calls the
standard /scim/v2/Users endpoints. Tokens are stored as Argon2 hashes
(scim_tokens table) with a 12-char display prefix; the plaintext scim-…
secret is shown once at creation.
Token management
| Method | Path | Role | Purpose |
|---|---|---|---|
POST | /api/v1/scim/tokens | owner | Mint a SCIM token for an org (one-time secret) |
GET | /api/v1/scim/tokens/{org_id} | admin+ | List tokens (prefix only) |
Provisioning endpoints
These follow the SCIM 2.0 wire spec and authenticate with
Authorization: Bearer scim-… (not a session cookie). They live under
/scim/v2, not /api/v1.
| Method | Path | Purpose |
|---|---|---|
POST | /scim/v2/Users | Provision a user (upsert by userName/email, add org membership) |
GET | /scim/v2/Users/{user_id} | Read a provisioned user scoped to the token's org |
DELETE | /scim/v2/Users/{user_id} | Deprovision — removes the user's membership in the token's org |
SCIM-provisioned users are created email_verified=True and default to the
viewer role within the org. A DELETE removes the OrgMember row (membership)
rather than hard-deleting the user account.
Data model
| Table | Holds |
|---|---|
saml_configs | One IdP config per org (entity IDs, SSO URL, cert, default role, enabled) |
scim_tokens | Argon2-hashed SCIM bearer tokens + prefix, scoped to an org |
org_members | Membership + role; written by both the SAML ACS and SCIM provisioning |
org_invites | One-time invite tokens (the manual alternative to SSO/SCIM) |
Notes & limits
- SAML and SCIM are organization-scoped — they presuppose an org exists and
the caller is an
owner. See the API reference for the org/member/invite endpoints. - The ACS sets the session cookie with
SameSite=Laxso the IdP-initiated POST navigation lands logged in. - SCIM deprovisioning removes org membership; it does not delete trace data, which remains owned by the underlying user account.