# Access control: keys, scopes and SSO

## Who can call the operator

A caller proves possession of a **ratified member key** (`/auth/challenge`, then `/auth/session`) and gets a session of at most an hour. Membership is re-checked on every request, so a member expelled by governance loses its session at once.

The member roster is the registry itself: it is quorum-ratified and public.

## Per-desk permissions: delegated keys

One member key would give every desk the same power. Instead, the member's **root key** signs a short-lived **delegation** for a desk key:

```bash
mirror-bander delegate --custody root-signer.json --delegate-public desk.pub.jwk --scopes read,webhooks --label platform-team --days 7 --out cert.json
```

| Scope | Lets the desk | Examples |
|---|---|---|
| `reconcile` | Submit legs and trade signals | `/reconcile`, `/pkyc/trigger`, `/exposure/commit`, disputes |
| `governance` | Submit member-signed governance events | `/registry/event`, charters, ceremonies |
| `webhooks` | Wire push endpoints | `/webhooks/*` |
| `read` | Read the member's own notices, certificates and exports | `/recall/notice`, `/audit/export`, `/path/certificate` |

- **Sign-in.** The desk signs in by presenting the certificate. Its session acts **as the member**, carries **only** the delegated scopes, and never outlives the certificate.
- **Enforcement.** The operator checks the scope before any member route runs; a missing scope is `403 scope`.
- **Revocation.** Expiry (30 days at most) is the default revocation. To revoke early, the member signs a `delegation.revoke` event. The desk's **live** session stops on its next request.
- **No chains.** A delegate cannot delegate: only a ratified root key can sign a delegation.
- **Legs.** They are still signed by the member key (or its HSM) through the bander; delegation governs API access.

## SSO and SCIM: at the member, never at the operator

The operator authenticates **keys**, not people. A label names a role ("platform-team", "ops-desk-2"); names and email addresses are refused.

Which person may use a desk key is decided **behind the bank's own SSO**:

1. A gateway inside the bank holds the desk keys, ideally in the HSM.
2. It lets SSO-authenticated staff through by their role.
3. It opens Mirror sessions with the matching desk key.

The bank's joiner, mover and leaver process (SCIM, the HR feed) stays where it is, and Mirror inherits it.

**Mirror will not hold a staff directory.** This is a refusal in [`/cannot`](/cannot.json) (`staff_directory`): an operator holding a bank's staff roster would hold personal data on a rail whose argument is that it holds almost nothing. There is therefore **no SAML, OIDC or SCIM endpoint on the operator**, by design.

## What is tested

- `server/delegation.test.js`:
  - desk sign-in and scope enforcement on real routes;
  - revocation cutting a live session;
  - another member unable to delegate or revoke on this member's behalf.
- `kernel/mirror-delegation.test.js`:
  - no chains, no widened scopes, no private keys, no names as labels;
  - at most 30 days.
