Skip to main content
The identity and enablement layer is a small set of governance entities owned by the IdP. This page describes them conceptually; the concrete storage schema is an internal implementation detail.
The IdP only authenticates. There is no permission catalogue, no per-client roles and no authorization tables. Fine-grained authorization lives in each client; the B Brands APIs use their existing internal RBAC.

1. Logical model

Common conventions on every entity: a UUID primary key, standard tracking fields (created/updated/deleted timestamps and soft-delete flags), restricted referential integrity, and row-level access controls.

2. Entities

OAuth client registry

Holds one record per registered client, with a stable client_handle (e.g. erp-dev), a human-visible display name, platform_type (agent, analytics, crm, erp, internal_tool, partner), trust_level (first_party, partner, public), status (active, suspended, revoked), id_token_alg (ES256 default, RS256 — the OIDC id_token_signed_response_alg: with RS256, the IdP re-signs the client’s id_token with its RSA key so libraries that only validate RS256, like Odoo’s OCA auth_oidc module, work unmodified), the registered redirect URIs (exact match), a per-client access-token TTL, and the provisioning webhook target plus its signing secret. The webhook secret is never returned after creation.

User × platform access

The central enablement entity. No role, no permissions. A user can have at most one active enablement per client. The access-token hook and the exchange both check status = 'active' and that the enablement has not expired. It tracks who granted access, optional expiry, and revocation data (when, by whom, reason).

Logs & audit

Consent decisions (approve/deny), the requested scopes, a correlation id, request metadata (IP, user agent) and references to the client and user.
Grant type (authorization_code / refresh_token / token_exchange), token type (oidc_identity / internal_exchange), jti, expiry and a correlation id. Append-only, best-effort.
The revoked token jti, token type, reason (e.g. oauth_revocation), expiry (for cleanup) and who revoked it.
Event type (user_provisioned / user_deprovisioned / user_suspended / user_reactivated), delivery status (pending / in_flight / delivered / failed / dead_letter), the payload, attempt count, next retry time and the last error.
The action (client created/updated/suspended/revoked, secret rotated, access granted/suspended/revoked/reactivated, …), the actor, the target client/user, a correlation id and request metadata.

3. Identity resolution & revocation

A single resolution routine is called by the access-token hook. It validates that the client is active and the user is enabled, and returns the identity payload (or a structured “not enabled” reason instead of raising, so the hook can answer a clean access_denied). The payload also carries the business-account dimension: the account bound to the user through the primary_user role and that account’s external system id (null when unmapped). A typical resolved payload:
Two revocation routines back the kill switch:
  • Revoke a single enablement for a user on one client.
  • Kill switch: revoke all of a user’s active/suspended enablements across every client at once. Each transition fires a provisioning event.

4. Provisioning lifecycle

A status change on the user × platform access entity is the single source of provisioning events:

5. Maintenance

The schema is evolved through versioned migrations. Periodic cleanup jobs run on a schedule: expired blacklist entries (daily), delivered events older than 30 days (weekly), and issuance/authorization logs older than 12 months archived to cold storage (monthly).