Skip to main content
The member realm stays in core (ADR-010, FS-CORE-0009). A member is an authenticated contact; a user is not.

Entities & invariants

Events emitted

identity.user.invited|joined|deactivated · identity.role.assigned|revoked · identity.api_key.created|rotated|revoked · identity.oauth.authorized|revoked · identity.impersonation.started|ended · identity.mfa.enabled|disabled

Endpoints

  • Auth: POST /v1/identity/auth/{sign-in,sign-up,sign-out,magic-link,passkey} — public, rate-limited
  • MFA: POST /v1/identity/mfa/{enroll,verify,disable}identity.mfa.*
  • Users and memberships: CRUD /v1/identity/users, /v1/identity/membershipsidentity.{resource}.{action}
  • Roles: CRUD /v1/identity/roles, POST /v1/identity/role-assignmentsidentity.roles.*
  • Machine credentials: CRUD /v1/identity/api-keys, /v1/identity/oauth-clients
  • OAuth2 provider: GET /oauth/authorize, POST /oauth/token, POST /oauth/revoke, GET /oauth/userinfo
  • Impersonation: POST /v1/identity/impersonations — Ops only, identity.impersonation.start

OAuth runs in both directions

Softcrum is an OAuth2/OIDC provider (FS-IDN-0007) so a partner tool can act on a tenant’s behalf and a tenant’s own site can offer “Sign in with Softcrum”, and an OAuth2/OIDC client (FS-IDN-0008) so a tenant’s staff can sign in through their own identity provider. Neither is the default; both are configuration, and a tenant may use both at once.

Non-negotiables

Every uniqueness constraint carries the tenant. Two realms, never overlapping. Every endpoint in the platform declares exactly one permission from this registry. Machines carry roles exactly like users. No module reads these tables directly — the API layer resolves the authorization context and passes it down.