> ## 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.

# Access lifecycle audit evidence (SCIM join / move / leave)

> Wire SCIM provisioning into the HIPAA minimum-necessary, SOC 2, and ISO 27001 access-control evidence trail — the joiner-mover-leaver story an auditor asks for: least-privilege group mapping, deprovisioning guarantees, the IdP-to-Orbit audit chain, and a worked provision-verify-deprovision loop.

# Access lifecycle audit evidence (SCIM join / move / leave)

[SCIM 2.0 provisioning](/compliance/scim-provisioning) configures the plumbing:
the Base URL, the Bearer token, the role mapping, the health check. This
page is what sits behind that plumbing when a HIPAA, SOC 2, or ISO 27001
reviewer asks the real question — *who had access to message data between
March and June, and prove they no longer do.* It is the access-lifecycle
evidence the [HIPAA posture guide](/compliance/hipaa-posture-guide) Section 1
(minimum necessary access), the [SOC 2 controls mapping](/compliance/soc2-controls)
(CC6.1 logical access), and the [ISO 27001 posture guide](/compliance/iso-27001-posture-guide)
(A.5.16 / A.8.2) all assume SCIM leaves behind.

<Warning>
  This page describes Orbit's platform controls. It is **not legal
  advice.** Whether your role mapping satisfies HIPAA § 164.308(a)(3),
  SOC 2 CC6.1, or ISO 27001 A.5.16 for your processing depends on your
  organization. Confirm with qualified counsel or your ISMS lead.
</Warning>

## The tenant-owned framing

Orbit's access surface follows the same model as the rest of the
compliance map ([posture overview](/compliance/posture-overview)):

* **Every control here defaults open or off.** A new workspace has no
  SCIM connection, no group mapping, and no designated PHI audiences.
  Nothing on this page is mandated, and nothing gates sending by itself.
  You assemble the posture; the platform enforces what you set.
* **Orbit is the conduit and the ledger.** It carries your IdP's
  provisioning decisions into workspace membership and records every
  join, move, and leave in the audit ledger — but the role mapping is
  yours, and the least-privilege judgement is yours.
* **The evidence reflects what you did.** An unconfigured group mapping
  exports as an open item; a reviewed mapping exports as a fact.
  Assemble the posture first; export second.

***

## Section 1 — The audit-question framing

An access-control reviewer — a HIPAA auditor working
§ 164.308(a)(3) (workforce security) and § 164.502(b) (minimum
necessary), a SOC 2 assessor mapping CC6.1, or an ISO 27001 reviewer
reading A.5.16 — does not ask for your SCIM configuration. They ask a
question shaped like this:

> *Show me every person who had access to patient message data between
> March 1 and June 30, what role each held, and that each who left no
> longer has access.*

Three records answer that question together, and none of them is
optional:

| Record | What it proves | Where it lives |
| - | - | - |
| **SCIM group mapping + sync history** | Which IdP group placed each person in which Orbit role, and when the last sync ran | `GET /api/v1/settings/scim/health` — provisioning counts and last-sync timestamps; the role config under **Settings → SCIM** |
| **SSO session records** | That the person actually signed in through your IdP during the window, not just that a seat existed | Your identity provider (Okta, Entra ID) — Orbit trusts the IdP for sign-in via [SAML SSO](/authentication); export the IdP session sign-in log for the same date range |
| **PHI access log** | That a person with access actually read PHI-bearing message content, with reason codes | `GET /api/v1/settings/hipaa/phi-access-log` — the append-only tenant log of every PHI read ([HIPAA controls](/compliance/hipaa)) |

The group mapping tells the auditor *who was entitled*; the SSO session
log tells them *who showed up*; the PHI access log tells them *who
touched PHI*. A reviewer who sees only the first and not the other two
has an entitlement list, not an access-control answer. Pull all three
for the same UTC-bounded range so the dates line up across records.

### Where the raw ledger lives

For the Orbit side of that trail, the [audit log export](/compliance/audit-export)
(`GET /api/v1/compliance/audit-export?from=YYYY-MM-DD&to=YYYY-MM-DD`)
bundles every audit event on the workspace into a signed download with
a 7-day TTL, and `…/:jobId/verify` replays the tamper-evident hash chain
so the reviewer can confirm the bundle is complete and unaltered. The
audit ledger is the single source the SCIM, role, and PHI-access rows
all land in — export it once over the reviewer's range rather than
hand-collecting screenshots.

***

## Section 2 — Least-privilege group mapping by job function

SCIM's `groupMapping` (set under **Settings → SCIM** or
`PATCH /api/v1/settings/scim`) maps an IdP group name to an Orbit role
on every sync. The mapping is the privilege vector the
[SCIM page](/compliance/scim-provisioning) warns about: a group named
`"Orbit Admins"` mapped to `owner` makes every member of that IdP group
a workspace owner on the next sync. Review the mapping before you enable
provisioning, and treat an unreviewed mapping as a finding in itself.

The five roles SCIM can assign are `owner`, `admin`, `developer`,
`billing`, and `viewer` (the `defaultRole` for users provisioned without
a group mapping). A least-privilege mapping by job function — the
starting point a HIPAA minimum-necessary or SOC 2 CC6.1 review expects
to see — looks like this:

| IdP group | Orbit role | What the role can do | Least-privilege rationale |
| - | - | - | - |
| `Orbit Support` | `viewer` | Read dashboards, contacts, and reports; no message-content writes | Support staff who look up context but never send or configure; the safe floor |
| `Orbit Ops` | `developer` | Everything `viewer` plus campaign and flow management; no billing or security settings | Operators who run campaigns and flows but do not touch billing or org-wide security |
| `Orbit Engineering` | `admin` | Everything `developer` plus security settings, team management, API keys; no ownership transfer or org deletion | Platform admins who manage configuration but are not the legal owner of the workspace |
| `Orbit Finance` | `billing` | Financial surfaces only; `403` on message-content endpoints | Finance staff who need invoices and usage but must not read PHI-bearing message content |
| `Orbit Owners` | `owner` | Full control, including ownership transfer and org deletion | The org owner — keep this group in your IdP's admin tier and review its membership quarterly; the fewest people possible |

Two rules keep this mapping defensible:

* **`defaultRole: viewer` is the safe floor.** Users provisioned without a
  group match land in `viewer`, so an unscoped IdP user cannot inherit
  `developer` or `admin` by accident. Set it to `viewer` and leave it
  unless a reviewed policy says otherwise.
* **`owner` is not a role you assign by group sync casually.** An owner
  can transfer ownership and delete the workspace. Keep the `owner`
  mapping to a single IdP group whose membership you review on a
  cadence — and document that cadence in the evidence binder.

A mapping where `Engineering` lands in `owner`, or where `defaultRole` is
`admin`, is the pattern a reviewer flags: it means every synced user
inherits more than their job function requires. If you cannot justify
each row in the table above to a reviewer in one sentence, tighten the
mapping before the audit, not during it.

***

## Section 3 — Deprovisioning guarantees

When someone leaves, the question is not just "did their seat go away"
but "can you prove they can no longer sign in, and did any AI agent
identity they owned stay live." A SCIM `DELETE /Users/{id}` — which Okta
sends on **Deactivate Users** and Entra ID sends on the deprovisioning
flow — does three things, each of which leaves evidence:

1. **Revokes the user's active sessions.** The user's Clerk session
   tokens are revoked immediately, so a sign-in attempt with a cached
   token fails. The [SOC 2 controls mapping](/compliance/soc2-controls)
   documents this under CC6.1 (session management): sessions are revoked
   on access changes via the session-revocation path.
2. **Suspends AI agent identities the user owned.** Removing an agent
   identity suspends it rather than deleting its configuration — so the
   agent stops running but its audit history and configuration record
   stay intact for the reviewer. This is the guarantee the
   [SCIM page](/compliance/scim-provisioning) states: deprovisioning
   suspends the agent identity rather than deleting it.
3. **Records the deprovisioning in the audit ledger.** The SCIM-driven
   create, update, and deprovision events are recorded in your
   organization's audit log — the same ledger the
   [audit export](/compliance/audit-export) bundles and chain-verifies.

### What the evidence looks like

The audit ledger row for a deprovisioning carries the actor (the IdP
identity that initiated the sync), the affected user, the timestamp,
and the action. An off-boarding flow that relies on SCIM therefore has a
defensible record even when no human clicked a button in the dashboard:
the IdP deprovisioning event, the session revocation, and the agent
suspension are all timestamped and chained. For a reviewer, the chain is:

1. The IdP logs the user's removal from the provisioning group (or their
   disable in the directory) — your IdP's audit trail.
2. The next SCIM sync sends `DELETE` to Orbit — recorded in the Orbit
   audit ledger.
3. The session revocation closes active sign-in — the next sign-in
   attempt fails.
4. The agent suspension stops automated runs — the agent identity's
   audit row shows the suspension.

If your written policy requires a time-bounded off-boarding SLA (the
platform-fixed ISO 27001 row cites a 24-hour off-boarding SLA for
Devotel's own staff; your SLA is yours), measure it from step 1 to
step 3 and keep the SCIM sync cadence tight enough to hit it. A daily
sync supports a next-business-day revocation; an hourly sync supports a
same-hour SLA.

***

## Section 4 — The audit chain: IdP events to Orbit audit events

An access-control reviewer reconciles two ledgers: what your IdP
recorded and what Orbit recorded. The correspondence is:

| IdP event (Okta / Entra ID) | Orbit audit event | Where the reviewer pulls it |
| - | - | - |
| User added to the `Orbit Engineering` group | `user.created` (via SCIM `POST /Users`) with the assigned `admin` role | Orbit audit ledger — `GET /api/v1/compliance/audit-export` over the range; your IdP's group-membership log |
| User moved from `Orbit Ops` to `Orbit Support` | `user.updated` (via SCIM `PATCH /Users`) with the role change `developer → viewer` | Orbit audit ledger; the IdP's group-change event |
| User removed from all `Orbit *` groups (off-boarding) | `user.deleted` (via SCIM `DELETE /Users`) — sessions revoked, agent identities suspended | Orbit audit ledger; the IdP's deactivation or group-removal event |
| Admin rotates the SCIM Bearer token | `scim.token.rotated` (owner-only) | Orbit audit ledger; **Settings → SCIM → Generate Bearer Token** |
| IdP sync runs and health check polled | Provisioning counts updated on `GET /api/v1/settings/scim/health` | The health endpoint's `lastRequest` / `lastSuccess` / `lastFailure` timestamps and provisioning counts |

For a HIPAA § 164.308(a)(3) (workforce security) review, the reviewer
wants the join and leave rows for the range; for SOC 2 CC6.1, they want
the role-change rows that prove access was modified when job function
changed; for ISO 27001 A.5.16 / A.8.2, they want the privileged-access
(`owner` / `admin`) assignment rows and the off-boarding rows. All three
read from the same Orbit audit ledger — the
[audit export](/compliance/audit-export) over the reviewer's date range
hands them the same rows, and `…/:jobId/verify` proves the chain is
intact.

### Where each record is pulled from

| Reviewer question | Pull from |
| - | - |
| Who was entitled to what, and when did it change | Orbit audit ledger via `GET /api/v1/compliance/audit-export` — SCIM role-assignment and role-change rows |
| Who actually signed in during the window | Your IdP's session sign-in log (Okta / Entra ID) — Orbit trusts the IdP for sign-in |
| Who read PHI-bearing message content | `GET /api/v1/settings/hipaa/phi-access-log` — the append-only PHI access log with reason codes |
| Did the exported ledger arrive complete and untampered | `GET /api/v1/compliance/audit-export/:jobId/verify` — `chain_valid`, `rows_checked`, and the daily Merkle roots |
| Is the SCIM connection healthy and which IdP is talking | `GET /api/v1/settings/scim/health` — `authenticationStatus`, `detectedIdp`, provisioning counts |

***

## Section 5 — Worked loop: provision, verify, deprovision, verify

A concrete run a reviewer can follow end to end. It provisions a user
from Okta, confirms the role in the PHI access log context, deprovisions
them, and confirms revocation.

### 1. Provision from Okta

Add the user to the `Orbit Support` IdP group in Okta (mapped to
`viewer` per the table in Section 2). On the next SCIM sync, Okta sends
`POST /Users` to `https://api.orbit.devotel.io/scim/v2/{orgSlug}/Users`.
Confirm the sync landed:

```bash theme={null}
curl https://api.orbit.devotel.io/api/v1/settings/scim/health \
  -H "X-API-Key: dv_live_sk_..."
```

The response's `authenticationStatus` reads `authenticating`, the
provisioning counts (`usersCreated`) increment, and the `detectedIdp`
reads `Okta` (inferred from the User-Agent). The user is now a `viewer`.

### 2. Verify the role in the access record

The user is entitled to read dashboards and contacts but not to write
message content. If HIPAA mode is active and the user reads a PHI-bearing
message, that read lands in the PHI access log with a reason code:

```bash theme={null}
curl "https://api.orbit.devotel.io/api/v1/settings/hipaa/phi-access-log?limit=50" \
  -H "X-API-Key: dv_live_sk_..."
```

The row carries the user id, the resource accessed, the reason, and the
timestamp — the *who touched PHI* half of the audit question. A `viewer`
who never reads PHI produces no PHI access log rows, which is itself the
least-privilege answer: entitlement without access is the goal.

### 3. Deprovision

Remove the user from all `Orbit *` groups in Okta (or disable them in
the directory). On the next sync, Okta sends
`DELETE /Users/{id}`. The deprovisioning revokes the user's active
sessions, suspends any agent identities they owned, and records the
event in the audit ledger.

### 4. Verify revocation

Pull the audit export for the range that spans the provision and the
deprovision, and chain-verify it:

```bash theme={null}
JOB=$(curl -s "https://api.orbit.devotel.io/api/v1/compliance/audit-export?from=2026-03-01&to=2026-06-30" \
  -H "X-API-Key: dv_live_sk_..." | jq -r '.data.id')

# poll to complete, then:
curl "https://api.orbit.devotel.io/api/v1/compliance/audit-export/$JOB/verify" \
  -H "X-API-Key: dv_live_sk_..." | jq '.data | {rows_checked, chain_valid, first_hash, last_hash}'
```

The bundle carries the `user.created` row from step 1, the PHI access
rows from step 2 (if any), and the `user.deleted` row from step 3.
`chain_valid: true` with `rows_checked` matching the exported count
proves the ledger is complete and unaltered for the range. The user's
next sign-in attempt fails — confirm against your IdP's session log if
the reviewer wants a third record.

That loop — provision, verify entitlement, deprovision, verify
revocation, export and chain-verify — is the joiner-mover-leaver
evidence a HIPAA, SOC 2, or ISO 27001 reviewer is asking for. Each step
leaves a row in the same audit ledger, and the chain-verify closes the
loop.

***

## What this page does not do

* **Orbit does not enforce least privilege for you.** The group mapping
  is your configuration; the platform assigns exactly the role you map.
  A reviewer's minimum-necessary judgement is yours, not the platform's.
* **Orbit does not certify your IdP.** Which IdP you trust, how its
  groups are governed, and how its session logs are retained are your
  calls. Orbit records the Orbit side of the chain; your IdP records its
  side.
* **Nothing here gates sending.** SCIM provisioning, role mapping, and
  the audit ledger are access controls, not message gates. The send-time
  gates that do exist are the ones you turned on, and each defaults open.
* **This is not legal advice.** The sequence documents Orbit's
  access-lifecycle surfaces; whether it satisfies HIPAA § 164.308(a)(3),
  SOC 2 CC6.1, or ISO 27001 A.5.16 for your processing is a call for your
  counsel and ISMS lead.

***

## Related references

* [SCIM 2.0 provisioning](/compliance/scim-provisioning) — the
  configuration mechanics this page builds on: Base URL, Bearer token,
  supported resources, role mapping, health checks, Okta and Entra ID
  setup.
* [HIPAA posture guide](/compliance/hipaa-posture-guide) — Section 1
  (minimum necessary access) and the PHI access log row this evidence
  trail feeds.
* [SOC 2 controls mapping](/compliance/soc2-controls) — CC6.1 logical
  access controls, the role hierarchy, and the audit-logging evidence.
* [ISO 27001 posture guide](/compliance/iso-27001-posture-guide) —
  A.5.16 / A.8.2 access control and privileged-access rows.
* [Audit log export](/compliance/audit-export) — the export and
  chain-verify endpoints the worked loop pulls.
* [HIPAA controls](/compliance/hipaa) — the PHI access log and
  minimum-necessary role surface.
* [Evidence binder](/compliance/evidence-binder) — the framework-mapped
  pack that assembles these rows into SOC 2, ISO 27001, GDPR, or HIPAA
  chapters.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.