Skip to content

Identity & provisioning runbooks (SSO, SCIM)

Use these runbooks to connect an organization to an identity provider. You can connect Okta, Microsoft Entra ID, or Google Workspace. You can also map identity-token claims and safely turn on enforced SSO. The SCIM runbooks tell you how to issue, rotate, and remove access. Each step names the applicable surface, environment variable, and artifact.

Status — Built, production rollout pending

Built vendor interop Planned

The enterprise identity layer — OIDC / SAML / SCIM / RBAC — is implemented and tested in the codebase. OIDC verification runs per-commit against Keycloak. SAML runs through a hardened sidecar with replay defense. The UI for these surfaces is part of the capability-gated enterprise workbench. OIDC also has live conformance coverage for Auth0, Okta, Microsoft Entra ID, and Google. SAML is verified against Keycloak. Production hosting, release promotion, and commercial SAML app conformance remain pending, Thus, the published release is still the local desktop workbench. The single source of truth for status is the roadmap & status table. If anything here and that table disagree, the table wins.

Read these runbooks as the operator procedure for an enterprise deployment, not as evidence that the hosted service is generally available today.

Before you connect anything: where your data goes

GaugeDesk orchestrates locally, but it does not run the model locally. The agent uses the third-party LLM provider you configure, so your members' prompts and the in-scope context for each run are sent to that provider over the network, in plaintext, today. Wiring SSO governs who may sign in and what role they hold — it does not change who can read plaintext. See Where your data goes before you onboard members.


What this layer governs (and what it does not)

The admin surfaces named here are workspace-administration controls — who may sign in, what role they hold, and what is on the audit record. They are orthogonal to the per-project authority and boundary decisions that protect the work itself. Those are evaluated the same way whether a member arrived by SSO or not.

Two kinds of guarantee live on this page, kept apart so claims stay defensible:

  • Structural, machine-checked. Fail-closed admission, the break-glass guard, and the monotone-policy law are properties of how the code decides — each paired with an adversarial test that fails if the protection is removed (modeled in Quint: rbac.qnt, abac.qnt). These hold by construction.
  • Policy / operational. IdP vendor interop, MFA enforcement, session lifetime, and your provider's retention terms depend on configuration or a third party. They are not invariants and are stated as such.

Roles are fixedowner / admin / member / viewer / billing — and default-deny: an unrecognized or absent role gets nothing. There is no policy editor or custom-role surface. That is deliberately deferred. A member or viewer sees no admin console at all. billing sees only billing. admin / owner see everything.


Runbook 1 — Connect an IdP over OIDC

OIDC covers all three target IdPs (Okta, Entra ID, Google Workspace) and is the recommended path. SAML support is built and verified against Keycloak. Commercial vendor-app conformance remains pending (see Runbook 2).

The connection lives on the SSO configuration surface (Administration contract B12), which reads the SSO-connection record and issues connection + enforcement commands. A failed test connection is operational state — it never becomes an admitted "connected" fact.

Steps

  1. At your IdP, register GaugeWright as an OIDC application (Web / confidential client). Set the redirect URI to your control plane's callback: https://<your-control-plane>/auth/callback. Note the issuer URL, the client id, and the client secret.
  2. In the admin console → SSO, choose protocol OIDC and enter:
    • Issuer — the OIDC issuer URL (the value the id-token's iss must match).
    • Audience(s) — the client id(s) the id-token's aud must match.
    • Metadata — the OIDC discovery URL (.../.well-known/openid-configuration).
  3. Run the test connection. GaugeWright fetches the issuer's JWKS and verifies it can validate a token's signature and the iss / aud / exp / nbf claims. A failure shows as operational state. Nothing is recorded as connected.
  4. Map claims (see Runbook 3) so the id-token's roles / region / tenant feed the access evaluator. The subject defaults to sub.
  5. Save. The connection record is admitted. Members can now sign in through the Sign-in affordance, which runs the auth-code flow: the browser is sent to /auth/login → your IdP → /auth/callback, which returns a verified id-token the client then carries as the bearer on gated /admin/* calls.
  6. Verify a real sign-in end-to-end before you enforce SSO (Runbook 4).

How verification actually works

The id-token signature is checked against the IdP's JWKS, and the verifier self-refreshes its signing keys from the issuer (with a refresh cooldown, so a flood of unknown-key tokens cannot stampede your IdP). A token whose signing key is already loaded but still fails is treated as a bad token, not a stale key set.

Use Okta's OIDC Web application. The issuer is your Okta org URL (or a custom authorization server). Roles typically ride in a custom roles claim you add through a claim/profile mapping — point GAUGEWRIGHT_OIDC_ROLES_CLAIM (or the connection's roles field) at it.

Register an app in Entra ID. The issuer is your tenant's v2.0 issuer. Entra emits group membership in the groups claim — use that for the roles mapping, or rely on SCIM group→role mapping (Runbook 5) for the authoritative role. Set the tenant claim if you scope by tenant.

Create an OAuth client in Google Cloud for your Workspace org. Google's id-token carries standard claims. Workspace does not emit rich group/role claims by default, so prefer SCIM group→role mapping for roles and use the id-token for subject/region.


Runbook 2 — Connect an IdP over SAML

Planned

SAML 2.0 is implemented in code (a hardened sidecar with replay defense) but is not a usable connect path yet — OIDC covers the three target IdPs today. When SAML goes live, the B12 surface will accept the IdP entityID as the issuer and the raw SAML metadata as the connection material, with the same test-connection and claim-mapping steps. Use OIDC until then.


Runbook 3 — Map claims to ABAC attributes

The verifier reads attributes, not raw tokens. The claim mapping decides which id-token claims feed which attribute. Each field has three layers, resolved in order: the connection's claim mapping (the per-connection home), then the matching GAUGEWRIGHT_OIDC_*_CLAIM env knob (the operator path), then unmapped — and unmapped is fail-closed: no attribute, because a missing attribute is safer than a wrong one.

Attribute Connection field Env knob Default if unset
Subject subject GAUGEWRIGHT_OIDC_SUBJECT_CLAIM sub
Roles roles GAUGEWRIGHT_OIDC_ROLES_CLAIM unmapped (no roles attribute)
Region region GAUGEWRIGHT_OIDC_REGION_CLAIM unmapped
Tenant tenant GAUGEWRIGHT_OIDC_TENANT_CLAIM unmapped

Roles claim ≠ console role

The roles claim feeds the attribute path that the access evaluator reads at the boundary. It does not set a member's RBAC console role — that is read from the org directory, not the token. The authoritative way to set a member's role from your IdP is SCIM group→role mapping (Runbook 5), not the id-token roles claim.

Other OIDC env knobs the operator path exposes, for completeness:

Knob Purpose
GAUGEWRIGHT_OIDC_REDIRECT_URI Override the callback URI (the value registered at the IdP)
GAUGEWRIGHT_OIDC_SCOPE Requested scopes (default openid profile email)
GAUGEWRIGHT_OIDC_POST_LOGIN_URL Where to send the browser after a successful sign-in

Steps

  1. Decide each attribute's source claim from your IdP's token (use the per-IdP tab in Runbook 1).
  2. Prefer the connection's claim mapping in B12 over env knobs — it is the admitted home and travels with the connection record. Use the env knobs only for headless/operator deployments without the UI.
  3. Leave an attribute unmapped if you do not use it. Unmapped is fail-closed. Do not point a field at a guessed claim "to be safe."
  4. After saving, sign in with a real account and confirm the resolved attributes match the token you expect.

Runbook 4 — Enforce SSO with a break-glass owner

Enforce-SSO requires all members to authenticate through the IdP. It is fail-safe by construction: the guard that keeps the last break-glass owner reachable is structural — enforced by the member routes themselves, independent of the enforce-SSO flag — so turning enforcement on can never lock out your last owner. This is a machine-checked property (abac.qnt: enforce-SSO can never remove the last owner), not a convenience setting.

Steps

  1. Designate a break-glass owner whose access does not depend on the IdP — a real human who can still reach the org if the IdP is down or misconfigured. The structural guard protects the last active owner. You must keep at least one deliberate break-glass account.
  2. Verify SSO sign-in works end-to-end for normal members (Runbook 1, step 6) before enabling enforcement. Do not enforce against an untested connection.
  3. Toggle enforce-SSO on the B12 surface. From here, members must sign in through the IdP. Domain-capture and SCIM govern who exists.
  4. Test the break-glass path: confirm the designated owner can still reach the console even with enforcement on. The guard means the toggle will refuse to strand your last owner, but you must verify that it works.

What enforce-SSO does and does not cover

Under enforce-SSO the MFA factor is enforced by your IdP, not by GaugeWright. GaugeWright's own MFA enforcement is Not implemented — set MFA as a sign-in requirement in your IdP. Session lifetime and idle-timeout are an org policy (Administration contract B15) the session layer honors. They are Built.


Runbook 5 — Issue and rotate a SCIM token

SCIM 2.0 lets your IdP create, update, and deactivate members directly. The provisioning surface (Administration contract B13) issues/rotates the token, shows last-sync status and errors, and maps IdP groups to roles/teams. The token authenticates your IdP's SCIM calls, which then drive membership commands.

The token is shown once and stored as a hash

The SCIM bearer token's plaintext is shown exactly once at issuance and is never persisted. GaugeWright stores only its hex-encoded SHA-256 (SEC-5: no secret at rest in plaintext). To check a presented token, GaugeWright hashes it and compares to the stored hash. With no token issued, nothing authenticates (fail-closed). This is an operational secret-handling property, not a machine-checked invariant.

Issue

  1. In the admin console → Provisioning (SCIM), choose Issue token.
  2. Copy the plaintext token immediately — it is shown once and never again. Store it in your IdP's SCIM configuration (the bearer credential).
  3. In your IdP, point the SCIM base URL at your control plane's SCIM endpoint and paste the token as the bearer.
  4. Run your IdP's SCIM test/sync. Confirm last-sync status shows success on the B13 surface (sync counts and latency are operational state, not product truth).

Rotate

  1. In Provisioning (SCIM), choose Rotate token. Rotating issues a new token and overwrites the stored hash, so the prior token stops authenticating immediately.
  2. Copy the new plaintext token (shown once) and update your IdP's SCIM configuration with it.
  3. Re-run the IdP sync and confirm last-sync success. If sync now fails, the IdP is still presenting the old (now-rejected) token — finish step 2.

Rotation is a hard cutover

There is no grace window. The moment you rotate, anything still presenting the old token is rejected. Rotate during a maintenance window if your IdP's SCIM sync is on a long interval.


Runbook 6 — Map IdP groups to roles, and verify offboarding revokes access

Group→role mapping is how your IdP authoritatively sets a member's workspace role. A mapping keys an IdP group name to a role (and an optional team). When SCIM provisions a user carrying that group, the member takes the mapped role/team instead of the default member. The first matching mapping wins in stable order. If no group matches, the member defaults to member.

SCIM-managed members appear read-only in the members directory (B11) with a "managed by your IdP" marker — their lifecycle is owned by B13, not by hand.

Map groups to roles

  1. In Provisioning (SCIM), add a mapping: IdP group → workspace role (optionally a team). Repeat per group you want to grant.
  2. Map only to the fixed roles: owner / admin / member / viewer / billing. There are no custom roles.
  3. Sync from the IdP and confirm members land on the expected role in the B11 directory.

Verify offboarding = access revoked

This is a security control, not a convenience, and the chain is made visible on the B13 surface. De-provisioning is structurally fail-closed (INV-20): an inactive member carries no role, so they are denied — there is no "deactivated but still allowed" state.

  1. Deactivate the user in your IdP (or remove them from the provisioning scope). Your IdP issues the SCIM deactivate.
  2. On B13, confirm the member now shows deprovisioned. The surface makes the offboarding → access-revoked chain explicit.
  3. Confirm denial: a deprovisioned member has no standing — role_of returns nothing for them, so any gated action fails closed. Verify they can no longer sign in to the console or reach gated /admin/* calls.
  4. History is untouched. Revocation blocks future access. It never rewrites the audit record (INV-18). The member's past actions remain on the append-only audit log (Administration contract B14), attributed to them.

Domain capture and SCIM

Separately from SCIM, verified-email-domain users can auto-join (B10): an address on a verified domain is captured. An unverified domain is refused (fail-closed). SCIM is the path for IdP-driven role assignment and offboarding. Domain capture is the path for self-service join on a trusted domain.


Known gaps & limitations (today)

Stated here, not only behind the trust site:

  • Production rollout is the gate. OIDC / SAML / SCIM / RBAC and the combined Administration UI are Built. Hosted production operation and release promotion are not generally available yet.
  • Commercial SAML conformance is pending. The adapter is verified against Keycloak. Use OIDC for the verified vendor paths.
  • MFA factor enforcement stays in your IdP. GaugeDesk carries the policy under enforce-SSO but does not implement a second factor itself.
  • Encryption at rest is Built (the AES-256-GCM seam) but awaits the KMS-managed data key. SIEM streaming has its sink built and awaits a per-deployment exporter.
  • No third-party certifications yet — SOC 2 Type II, DPA, and a penetration test are Planned.
  • Inference is remote. SSO does not change this: prompts and in-scope context go to the third-party provider each member configures. See Where your data goes.

Where to go next

Deep links for the curious (optional): the surface contracts are Administration B12 (SSO) and B13 (SCIM). The structural guarantees are INV-20 (fail-closed), INV-18 (append-only history), and the Quint models rbac.qnt / abac.qnt.