Skip to main content

Identity federation: SAML and SCIM

Identity federation answers two separate questions: which users exist in your Orbit organization (provisioning) and how those users sign in (authentication). Orbit covers provisioning with SCIM 2.0 and authentication with SAML 2.0 — two independent, per-organization controls that pair well together but never imply each other. This page explains the conceptual model the task guides assume; for the step-by-step walkthroughs, see Enroll SAML SSO and Wire SCIM provisioning, and for the credential classes involved, Authentication and session model.

1. What gets federated

Federation moves dashboard users and the groups they belong to — never API keys, never your tenants’ end customers. The two protocols split the work:
  • SCIM (System for Cross-domain Identity Management) manages membership. Your IdP (Okta, Microsoft Entra ID, OneLogin, any RFC 7643/7644 client) pushes user and group changes to Orbit. A person assigned to the Orbit application in your IdP appears in your organization ahead of their first login — an account exists, with a role, before anyone signs in.
  • SAML (Security Assertion Markup Language) manages sign-in. On each login, the IdP sends a signed assertion naming the user; Orbit verifies the signature against your stored certificate and mints a dashboard session token. Assertion → session, on every login.
The distinction matters operationally. A SAML-first-login flow without SCIM works only if Orbit can find a matching member — with no provisioning surface, someone must invite the person manually first. With SCIM in place, the account is provisioned ahead of the first assertion, and login succeeds on day one.

2. The provisioning lifecycle

Every IdP-managed account moves through the same four events, driven by your IdP’s assignment state:
  1. Create — assigning someone to the Orbit app produces a POST /Users. Orbit creates the account at the role your SCIM settings resolve (default role plus group mapping). The create is keyed on email, so an IdP retry after a partial failure lands on the same account rather than duplicating it.
  2. Update — name, email, username changes in the directory arrive as PUT (full-replace, Okta’s habit) or PATCH (partial, Entra’s habit). Both are equivalent here; only the mapped fields apply.
  3. Deactivate — unassigning a person sends active: false. This is a suspend, not a delete: the account’s row stays, sessions stop, the user can no longer sign in, but history and ownership remain. Reactivating in the IdP (active: true or a fresh create) resurrects the same account with its role and history intact.
  4. Deprovision — the IdP sends DELETE /Users/:id. This is the real removal: active sessions and API access are revoked, the member leaves the roster, and owned assets transfer to an owner. A repeated DELETE answers 404, so IdP retries are safe.
Deactivate-vs-delete is the distinction operators get wrong most often. Deactivate is routine and reversible — a leave of absence, a contractor’s gap, a scoping change in the IdP. Deprovision is the final step for someone who genuinely left.

3. The SCIM model in Orbit

The SCIM surface lives at the API root — not under /api/v1:
  • Base URL: https://api.orbit.devotel.io/scim/v2/{orgSlug} — every call is keyed by your organization slug.
  • Resources: /Users and /Groups (list, get, create via POST, replace via PUT, modify via PATCH, remove via DELETE on the :id suffix), plus a /Agents resource that mirrors AI-agent provisioning under the same token and rate limit.
  • Discovery: /ServiceProviderConfig, /ResourceTypes, and /Schemas describe the surface for IdP auto-configuration.
  • Auth is a dedicated Bearer token (shown once at generation, stored as a hash), rate-limited per token. It is not an API key and not a session token — valid on these endpoints only.
Attribute mapping is intentionally narrow. Orbit accepts the standard SCIM user schema, reads four fields, and accepts-and-ignores everything else (locale, timezone, addresses, enterprise extensions): Groups are synthesized from your role map, not free-standing entities. For each role referenced in groupMapping, Orbit exposes one SCIM group (id role:{role}); PATCHing members into it re-maps those users to the mapped role on each sync. Group push is optional — without a map, every provisioned user lands on defaultRole. A role ceiling bounds what any push can assign; an over-ceiling push is refused and nothing changes.

4. The first-login sequence

The canonical enterprise order — SCIM provisioning before SAML first login — looks like this: Each step is independently protected: the SCIM create carries the Bearer token, the SAML callback verifies the signature against your stored IdP certificate, and the session is issued only when the assertion’s mapped email matches an existing member. A SCIM-provisioned-but-inactive account (active: false) fails at that match step — provisioning created the row, but authentication still checks the account is enabled.

5. Tenant ownership of the posture

SAML and SCIM are tenant-owned controls, in the same register as every other compliance-relevant surface on the platform:
  • Configuration is org-scoped and owner-gated. SAML lives under Settings → Security, SCIM under Settings → SCIM; reading the config is broader, but only an owner writes it.
  • Nothing is platform-mandated. An organization without an IdP keeps password sign-in and manual membership forever. Orbit requires neither protocol for any certification, and asserts no claims about your IdP topology — the posture is yours to adopt, scale, or retire.
  • Enforcement is staged, never assumed. enabled turns SSO on; enforced additionally disables password sign-in. The guides walk you through verifying a second owner on SSO before enforcing, and disabling/enforcing-off both restore password sign-in without touching the stored configuration.
  • Break-glass thinking is on you. Because enforcement is org-scoped, your fallback for an IdP outage is an owner reverting enforcement from a working session — plan for that (a verified second owner) before you enforce, not after a lockout.

6. Anti-patterns

Avoid these failure modes at the model level — each one has bitten a real rollout:
  1. Mixing SSO and password for the same user as the steady state. enforced: false is a staging posture while you test, not a target. Left in place permanently, it keeps credential-phishing surface open and muddies which login method — and which offboarding signal — you trust.
  2. Treating a SCIM-deactivated user as deleted. active: false suspends; it does not remove. If your audit story or your “who still has access” review assumes removal, you will report the wrong thing. Send DELETE for real departures; deactivate for every temporary assignment change.
  3. SAML without provisioning, then blaming login. The assertion matches an email against an existing member. If nobody provisioned or invited the user, the most-configured SAML flow still fails at the callback. Pair the protocols, or keep an explicit manual-invite path.
  4. Mapping IdP groups to owner. The group map is a privilege assignment: every member of a mapped IdP group gets the mapped role on each sync. Keep owner assignment in the dashboard and let group push target admin or below — the role ceiling exists to refuse pushes that overshoot.
  5. Provisioning active: false as an “invitation”. An inactive account exists but cannot sign in. A person who should be able to log in today needs an active account; send active: false only when you mean “pre-stage the row, enable later.”

See also