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

# Outbound SSO to Claude

> SAML identity-provider architecture, pilot decisions, and delivery boundaries

Tuturuuu is the proposed SAML 2.0 identity provider: an invited Claude organization
member signs into Claude through WorkOS using a Tuturuuu account. This is distinct
from inbound enterprise sign-in to Tuturuuu and from internal cross-app sessions.
No Supabase bearer token is shared with Claude.

## Pilot decisions

The pilot is SP-initiated and defaults to denied access. A future enabled client
selects exactly one active nonpersonal workspace. Each user needs current MEMBER
status, an explicit client assignment, a confirmed email in an approved domain,
fresh verified MFA no older than ten minutes, and identity-sharing approval on
every login. Guests, invitations and email-domain matches alone confer no access.
No workspace or test population has been selected by the protocol fixture.

Share only a stable random pairwise NameID/`id`, confirmed `email`, `firstName`
and `lastName`. Persist subjects per client/Auth account; do not derive them from
email or recycle them. An email change requires fresh verification and operator
review of Claude linking behavior before restoring SSO. Names are presentation,
never authorization. Claude owns roles, seats and invite-only provisioning.

The pilot excludes OIDC, SCIM, groups, IdP-initiated login and single logout.
Tuturuuu logout does not imply termination of an existing Claude session.
These decisions apply to future outbound SSO Web/consent/management surfaces;
ordinary Tuturuuu sign-in and cross-app session policy retain their own rules.

## Phase 1 protocol boundary

`packages/sso` provides strict Zod configuration/request/identity/assurance
contracts, bounded Redirect and POST AuthnRequest decoding, pinned request
signatures when required, signed response/assertion construction and public IdP
metadata without SLO. Clock, signer and ID generation are injected. Portable
entrypoints have no framework imports; the implementation targets Node crypto
and zlib for the future Next.js Node runtime on Vercel.

The selected libraries are `xml-crypto` 6.4.0 and `@xmldom/xmldom` 0.9.12.
RSA-SHA256 signatures, SHA256 digests and exclusive canonicalization are supplied
by the library. Request admission rejects unknown SPs, exact-URL mismatches,
stale requests, unsupported NameID/authentication contexts, passive interactions,
duplicate IDs/parameters, DTDs and oversized compressed/expanded XML. Unsigned
requests require an explicitly unsigned profile and do not authenticate the SP.

Assertions expire after two minutes and bind Audience, Recipient, Destination
and InResponseTo. The only supported NameID format is persistent; the connection's
actual requirements must be confirmed before enabling it. For both request
bindings, NameIDPolicy or AllowCreate omission means false, including signed
requests. Only explicit true/1 permits the future caller to allocate a subject;
otherwise it must find an existing mapping or deny. These defaults apply to the
portable protocol and future outbound SSO adapters, with no unsigned-request
exception. See `packages/sso/src/__tests__/security-review.test.ts` for omission
and invalid-boolean regression coverage. REFEDS MFA context
requires a future adapter to prove primary authentication and current TOTP MFA;
the package cannot establish assurance from a supplied timestamp alone.

Phase 1 adds no routes, UI, migrations, live clients or hosted configuration.
Metadata generation is a library function, not a published metadata endpoint.
Do not expose the protocol functions as an issuance API without the later gates.

## Phase 2 persistence boundary

Six additive migrations (`20261022100000` through `20261022100005`) introduce
`manage_sso_clients` and eight RLS-enabled private tables: `sso_clients`,
`sso_saml_clients`, `sso_assignments`, `sso_subjects`, `sso_disclosure_grants`,
`sso_transactions`, `sso_signing_keys` and `sso_audit_events`. All children carry
`ws_id` and composite tenant foreign keys. Creation always starts disabled;
client changes require an expected policy revision. The initial profile supports
only persistent NameID and one to eight exact HTTPS ACS destinations, without
credentials, fragments or custom ports. Configuration stores approved email
domains; authoritative email/domain enforcement belongs to phase 3.

Browser roles and `service_role` have no direct table privileges. Management is
through service-only `sso_manage_client` and `sso_set_assignment` RPCs. Both require
a current MEMBER in an active nonpersonal workspace with effective
`manage_sso_clients` permission (including the existing creator/admin semantics).
The server must resolve the authenticated actor before calling them; an actor ID
is a trusted server input, never a browser authorization claim.

Service-only `sso_create_transaction` reserves a request hash uniquely per client,
stores InResponseTo and an exact configured ACS, and caps expiry at five minutes.
Opaque handles, browser/session bindings and RelayState are hashes; raw RelayState
and assertions are absent. `sso_record_consent` records one immutable per-login
approval or denial for the fixed identity attribute list, binding actor, policy,
browser and session. Denial burns the transaction. `sso_consume_transaction` takes
row locks, rejects expired/used transactions, rechecks enabled client, policy,
current MEMBER and active assignment, and requires the matching approval and
bindings. The validated request's `allow_create` is persisted with default false;
allocation requires explicit true, while false can reuse an existing mapping.
Consumption, random 256-bit pairwise subject allocation and audit append
commit together. Concurrent consumers yield one winner and a replay error.

`authenticated` users can call `sso_read_own_disclosures(ws_id)` to read up to 100
of their own receipts. Its actor comes exclusively from `auth.uid()`. Other users
and anonymous callers cannot read those receipts. Disclosure receipts and audit
rows reject updates and deletes; audit appends expose only bounded event codes
and correlation IDs. `sso_append_audit` is service-only and requires a consumed,
approved transaction for issuance events. A signed event records the issuer's
observation; it does not prove Claude accepted the response.

Signing-key rows contain only a public certificate, kid, status, revision and
validity/rotation timestamps. A partial unique index permits at most one active
key per client. Certificate syntax constraints reject private-key PEM; the future
signer must validate the actual X.509 certificate and key match. No private key,
secret reference, key import/rotation RPC or signer route is added by this phase.
Subjects reference `auth.users`, so actual Auth deletion clears their user link
while reserving the random value. Auth deletion also clears client/assignment
creator attribution and deletes assignments and actor-bound transactions, even
though the public user row remains. Membership deletion cascades assignments;
MEMBER-to-GUEST demotion deletes them too. Rejoining or later promotion requires
an explicit new assignment. This rule applies to every phase 2 SSO client.

Workspace hard deletion cascades clients, protocol profiles, assignments, subjects,
transactions and public signing-key metadata, including disabled clients. Immutable
disclosure receipts and audit events retain denormalized workspace/client/actor/
transaction UUIDs without parent foreign keys. These historical receipts cannot
authorize a login without a live transaction and current membership/assignment.
Cleanup never disables or bypasses their append-only triggers. All eight tables
force RLS; approved definer RPCs retain their PostgreSQL BYPASSRLS owner, while a
non-BYPASSRLS table owner is subject to the policies.
Receipt/audit actors are UUID-only correlation values without deletion-blocking
user foreign keys; retention and pseudonymization require the phase 5 operating
policy. There is no automatic retention job in this phase.

### Database verification

From the repository root, run:

```sh theme={null}
ttr resources run -- node apps/database/scripts/verify-sso-persistence.mjs
```

The runner stages the complete migration history into an owned disposable
Supabase project, applies it with `supabase start` and `supabase db reset`, runs
`sso-persistence.sql` with strict pgTAP parsing, and drives a real two-connection
consume race. It generates `packages/types/src/supabase.ts` from that same applied
`public,private,storage` schema, then stops only the owned database without backup.
Synthetic race rows are committed only inside the disposable database and vanish
with its teardown; immutable audit rows are never bypassed for fixture cleanup.
Each race uses fresh UUIDs so repeat runs preserve retained user/workspace history.
The pgTAP packet covers membership removal/rejoin, demotion/promotion, real Auth
deletion (including retained public users), creator and workspace deletion,
byte-identical retained history, and a non-BYPASSRLS table owner. The separate race
requires one winner, one replay rejection, one subject and one consume audit.
It also races membership deletion and assignment deactivation against consume in
both orders. The holder observes its own PID blocking the competitor before it
commits: revocation first must deny consume without a subject or consume audit;
consume first must commit before revocation can commit. Both orders deny a later
consume. Assignment deactivation uses direct SQL so the management RPC's client
lock cannot mask missing authorization-row locks. Keep lock-removal negative
controls confined to a disposable database; never alter production migrations
to make the harness pass.

When the committed base type snapshot already lags its applied schema, generate
both the clean base and candidate using the same CLI and formatter. Apply their
generated delta to the committed base with a three-way merge, failing on conflicts;
exclude unrelated baseline drift rather than manually editing generated objects.
The SSO-only committed type delta intentionally excludes existing employee-profile
objects absent from the base snapshot. The workflow artifact still contains the
complete applied schema. Check `packages/users-core` as well as the types package
after generation because new FK relationships affect nested select inference.

The runner prints a schema snapshot digest and recovery directory for a failed
cleanup. Use the existing isolated lifecycle cleanup procedure for that directory.
The `SSO persistence database contract` CI workflow repeats this on the exact PR
head. No application stack or build is needed for this check.

These primitives do not establish Auth account status, confirmed email, MFA,
request XML validation, key selection or an issuance permit. Phase 3 must provide
those checks, recheck current key/policy state after signing, and burn the original
transaction on an unknown signing outcome. Never interpret a consumed database
row as permission to retry or emit an assertion without those service gates.

## Verification and remaining work

`packages/sso/src/__tests__` drives generated signatures through Node-SAML's SP
consumer with disposable in-memory keys. Negative coverage includes wrapping,
tampered claims, unsigned assertions, wrong audience/ACS, expiration, replayed
InResponseTo, unknown SPs and deflate bombs. Node-SAML uses the same underlying
signature library; independent SAML parsing is not independent crypto validation.
Parser and XML-signature library failures expose fixed protocol error messages
without request-derived diagnostics. Wrapping regressions retain an intact signed
assertion beside a distinct unsigned attacker assertion, verify both original
assertion and renewed outer signatures, and assert semantic rejection.
The harness adds exact Destination/Recipient checks because Node-SAML 5.1.0 does
not enforce them for login responses. See `packages/sso/README.md` for dependency
advisories, limits, reproduction commands and the samlify evaluation.

Phase 2 supplies the private database primitives described above. Phase 3 supplies
authoritative Auth/MFA/eligibility reads,
disclosure enforcement, key/policy revision fences, durable audit and disabled
Web routes. Phase 4 supplies bilingual management and per-login consent UI.
Phase 5 supplies rotation, compromise/disable procedures, an explicitly selected
test workspace and connection, exact-commit CI/runtime acceptance and real Claude
SSO tests. Runtime profile verification and actual Claude login remain unrun.

Run focused tests through `ttr resources run -- bun run --cwd packages/sso test`
and the package's `type-check` script. Require applicable exact-commit CI before
integration; no local release builds or production configuration changes are
part of this phase.


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