> ## Documentation Index
> Fetch the complete documentation index at: https://docs.orbit.devotel.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Identity federation: SAML and SCIM

> The conceptual model of Orbit identity federation — what SAML and SCIM each control, the provisioning lifecycle from create to deprovision, attribute and group mapping, the first-login sequence, and the tenant-owned posture both protocols share.

# 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](/guides/saml-sso-enrollment) and
[Wire SCIM provisioning](/guides/scim-provisioning), and for the credential
classes involved, [Authentication and session model](/concepts/authentication-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):

| Orbit user field | SCIM attribute                                                               |
| ---------------- | ---------------------------------------------------------------------------- |
| Email / username | `userName`, or the `primary` entry of `emails` (`userName` wins on conflict) |
| Name             | `displayName`, or `name.givenName` + `name.familyName`                       |
| Active flag      | `active`                                                                     |
| IdP-side id      | `externalId` (stored as the directory's stable identifier, optional)         |

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:

```mermaid theme={null}
sequenceDiagram
    participant Admin as IdP admin
    participant IdP as Identity provider
    participant SCIM as Orbit SCIM endpoint
    participant User as Team member
    participant SAML as Orbit SAML login
    participant API as Orbit API

    Admin->>IdP: Assign user to Orbit app
    IdP->>SCIM: POST /scim/v2/{orgSlug}/Users
    SCIM-->>IdP: 201 Created (account ready at resolved role)
    Note over User: Any time later…
    User->>SAML: GET /auth/saml/{orgSlug}/login
    SAML-->>User: 302 to IdP
    User->>IdP: Authenticate (MFA, policies)
    IdP->>SAML: POST signed assertion to /auth/saml/{orgSlug}/callback
    SAML->>API: Match assertion email to provisioned member
    API-->>User: Session token minted — dashboard lands
```

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

* [Enroll SAML SSO](/guides/saml-sso-enrollment) — the step-by-step SAML
  setup, attribute defaults for Okta and Entra, and the failure table.
* [Wire SCIM provisioning](/guides/scim-provisioning) — IdP walkthroughs,
  attribute and group mapping, lifecycle semantics, and sync errors.
* [SCIM 2.0 provisioning reference](/compliance/scim-provisioning) — the
  endpoint table, token generation, and health-check fields.
* [Authentication and session model](/concepts/authentication-model) — the
  three credential classes (API keys, session tokens, SCIM token) and how
  the server tells them apart.
* [Roles, teams & permissions](/concepts/roles-teams-permissions) — the
  role vocabulary (`owner`…`viewer`) that SCIM group push assigns.
* [Tenant isolation](/concepts/tenant-isolation) — how the org-scoped
  configuration of both protocols rides the tenant model.
