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

# SSO & SCIM

> Enterprise SAML 2.0 single sign-on and SCIM 2.0 directory provisioning.

## Overview

**Enterprise** teams can connect their identity provider (Okta, Azure AD, OneLogin, Ping Identity) for **SAML 2.0 single sign-on** (via WorkOS SSO) and **SCIM 2.0** automated user provisioning. The team is the SSO / SCIM **organization boundary** — one IdP integration manages one team's membership.

<Info>
  SSO and SCIM are **Enterprise-plan only**. The server re-checks the plan on **every** request: if the team's subscription is not an active Enterprise plan, SSO configuration and all `/scim/v2/*` calls are rejected with `403 enterprise_plan_required`. A lapsed subscription disables provisioning immediately.
</Info>

***

## SAML 2.0 Single Sign-On

SAML assertion verification is handled by **WorkOS SSO**. The dashboard **SSO & SCIM** page (`/settings`) surfaces the values you paste into your IdP and stores your IdP descriptor:

| Service Provider value      | Where it goes in your IdP        |
| --------------------------- | -------------------------------- |
| **SP Entity ID (Audience)** | IdP "Audience URI"               |
| **ACS (Reply) URL**         | IdP "Single sign-on / Reply URL" |

You enter your IdP's metadata URL or Entity ID along with your corporate email domains. The descriptor is stored in `sso_configs` and reconciled into WorkOS SSO out-of-band.

***

## SCIM 2.0 Provisioning

SCIM lets your IdP create, update, and deactivate team members automatically. Point your IdP's SCIM connector at:

```text theme={null}
Base URL:  https://ksrlmubaxzwufziwarps.supabase.co/functions/v1/v2-agent-state/scim/v2
Auth:      Bearer <scim_… token issued on the SSO & SCIM page>
```

SCIM bearer tokens are minted per team on the dashboard and shown **once** at creation. They are stored only as a SHA-256 hash and can be revoked at any time.

### Supported resources

| Method & path               | Behavior                                        |
| --------------------------- | ----------------------------------------------- |
| `GET /scim/v2/Users`        | List members (supports `filter=userName eq "…"` |
| `POST /scim/v2/Users`       | Provision a member (lands as **`pending`**)     |
| `GET /scim/v2/Users/:id`    | Fetch one member                                |
| `PATCH /scim/v2/Users/:id`  | Update role, or `active=false` to deprovision   |
| `DELETE /scim/v2/Users/:id` | Deprovision: **revoke key grant** + deactivate  |
| `GET /scim/v2/Groups`       | The team, with its active roster                |

### Provisioning and the zero-knowledge boundary

<Warning>
  SCIM moves **directory metadata only** — it never mints or wraps an encryption key. A newly-provisioned user is a **`pending`** member with **no key grant**, so they cannot yet decrypt shared team memory. An admin issues their key grant client-side when they accept (the DEK is wrapped to the new member's public key in the browser — the server never sees it).
</Warning>

Deprovisioning (`DELETE` or `PATCH active=false`) **revokes the member's key grant** — removing their ability to decrypt — and marks the membership inactive. The grant revocation is the security-critical step and happens first.

### Tamper-Evident Audit Ledger Integration

Every provisioning event feeds the append-only SHA-256 tamper-evident audit ledger (`audit_entries`): `member.add` on provision, `member.update` on role change, and `member.remove` on deprovision, plus `sso.config_update`, `scim.token_issue`, and `scim.token_revoke` for configuration changes.
