Groundwork for SCIM v2 provisioning (RFC 7643/7644), targeting Entra ID:
- New scim_api_key table (sqlite/mysql/postgresql migrations) storing a
sha256 digest of a per-organization static bearer secret. An active row
doubles as per-org SCIM enablement; org deletion cleans it up.
- ScimToken request guard modeled on PublicToken: pre-auth rate limiting,
scim_enabled gate, token format scim_v1.<org>.<secret>, token-org vs
path-org check before any DB work, constant-time digest compare with a
dummy compare on miss. All failure causes log server-side and surface as
one uniform SCIM-enveloped 401.
- SCIM error envelope + catchers so every response under /scim (400/401/
404/429/500) is application/scim+json.
- Discovery endpoints (ServiceProviderConfig, ResourceTypes, Schemas).
- Admin-session management endpoints under /api: generate/rotate (plaintext
shown once), delete, and status; guarded by AdminHeaders plus password or
OTP re-auth, mirroring rotate_api_key.
- Config: scim_enabled (default off) and SCIM rate limiter settings.
- Test infrastructure: hermetic pre-main env bootstrap (test-support crate,
keeps CONFIG away from the developer's .env and data), Rocket local-client
harness on temp sqlite, authz matrix asserting byte-identical 401 bodies,
rate limiter drain test.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>