Summary
Add a SCIM 2.0 provisioning endpoint so an organization's IdP can create, update,
and (most importantly) deactivate akari accounts out of band, before and
independent of any login. JIT provisioning (option 2, OIDC) creates a user on
first login; SCIM adds the other half of lifecycle: users can exist before they
ever sign in, and deprovisioning on offboard actually disables the akari account
instead of leaving it live.
This is option 3 of the federated-identity plan, an add-on to the login mechanism
rather than a replacement: pair it with option 1 (proxy header) or option 2 (OIDC)
for the actual authentication. See the "Federated identity behind a trusted proxy"
section in docs/DESIGN.md.
What already exists
- The federated-account model from option 1: nullable
users.password_hash and
users.auth_source (migration 0034_federated_users.sql).
- Bearer-token auth with hashed opaque tokens and scopes
(internal/server/httpapi/auth.go, internal/server/store/auth.go). SCIM's
bearer auth can reuse this shape.
Scope
- Implement the SCIM 2.0 core (RFC 7643 schema, RFC 7644 protocol) for Users, at
minimum:
POST /scim/v2/Users (create), GET /scim/v2/Users/{id} and list with
filtering on userName, PATCH/PUT (update, including the active flag),
DELETE (or soft-deactivate via active=false).
GET /scim/v2/ServiceProviderConfig, /Schemas, /ResourceTypes as required
by strict SCIM clients.
- Data model:
- Add an
active/deactivated_at notion to users so a SCIM active=false
disables the account: resolve must reject a deactivated user across every
credential path (cookie, proxy header, OIDC session, Bearer token), and its
web sessions and tokens should be revoked on deactivation.
- Store the SCIM
externalId and reconcile it with the OIDC external-subject
key so a SCIM-provisioned user and the same person's first OIDC login resolve
to one account, not two.
- Extend the
auth_source CHECK to include 'scim' (or treat SCIM as
provisioning metadata orthogonal to the login source; decide during design).
- Auth for the SCIM endpoint itself: a dedicated bearer credential (a new token
scope, e.g. scim) that the IdP presents, issued and revocable by an admin.
Reuse the existing hashed-token machinery.
- Config:
AKARI_SCIM_ENABLED (off by default) plus whatever the token issuance
path needs.
Verification
- Integration tests: create a user via SCIM (exists before any login), a
subsequent login (proxy or OIDC) resolves the same account, active=false
immediately locks the user out on every credential path and kills live sessions,
and reactivation restores access.
- SCIM bearer auth rejects an unscoped or missing token.
go test ./... green under eph.
Non-goals
- Groups/roles sync (a possible follow-up; start with Users + active lifecycle).
- Being the authentication mechanism: SCIM provisions, it does not log anyone in.
Summary
Add a SCIM 2.0 provisioning endpoint so an organization's IdP can create, update,
and (most importantly) deactivate akari accounts out of band, before and
independent of any login. JIT provisioning (option 2, OIDC) creates a user on
first login; SCIM adds the other half of lifecycle: users can exist before they
ever sign in, and deprovisioning on offboard actually disables the akari account
instead of leaving it live.
This is option 3 of the federated-identity plan, an add-on to the login mechanism
rather than a replacement: pair it with option 1 (proxy header) or option 2 (OIDC)
for the actual authentication. See the "Federated identity behind a trusted proxy"
section in docs/DESIGN.md.
What already exists
users.password_hashandusers.auth_source(migration0034_federated_users.sql).(
internal/server/httpapi/auth.go,internal/server/store/auth.go). SCIM'sbearer auth can reuse this shape.
Scope
minimum:
POST /scim/v2/Users(create),GET /scim/v2/Users/{id}and list withfiltering on
userName,PATCH/PUT(update, including theactiveflag),DELETE(or soft-deactivate viaactive=false).GET /scim/v2/ServiceProviderConfig,/Schemas,/ResourceTypesas requiredby strict SCIM clients.
active/deactivated_atnotion tousersso a SCIMactive=falsedisables the account:
resolvemust reject a deactivated user across everycredential path (cookie, proxy header, OIDC session, Bearer token), and its
web sessions and tokens should be revoked on deactivation.
externalIdand reconcile it with the OIDC external-subjectkey so a SCIM-provisioned user and the same person's first OIDC login resolve
to one account, not two.
auth_sourceCHECK to include'scim'(or treat SCIM asprovisioning metadata orthogonal to the login source; decide during design).
scope, e.g.
scim) that the IdP presents, issued and revocable by an admin.Reuse the existing hashed-token machinery.
AKARI_SCIM_ENABLED(off by default) plus whatever the token issuancepath needs.
Verification
subsequent login (proxy or OIDC) resolves the same account,
active=falseimmediately locks the user out on every credential path and kills live sessions,
and reactivation restores access.
go test ./...green under eph.Non-goals