
## What federation gives you

By default an org's operators authenticate through the daevix identity backend.
**Federation** points an org at *your own* upstream identity provider instead, so:

- your people sign in with their existing corporate accounts (SSO), and
- the **group memberships** your IdP already manages flow into daevix as the
  `urn:dvx:groups` claim, where you bind them to roles with group-scoped grants.

Membership stays authoritative **upstream** — daevix never copies your directory.
It only translates "which groups does this token claim" into the group principals
your grants are keyed on. Add or remove someone from a group in your IdP and the
change takes effect on their next token, with nothing to sync on the daevix side.

## Before you start

- You need `idp:manage` in the org (the `admin` role includes it). Federation is
  a distinct capability precisely because it introduces a new trust dependency —
  your org is trusting an external IdP for authorization-relevant group claims.
- Register an OAuth/OIDC client (or a SAML application) with your IdP, pointed at
  the daevix identity backend's callback. Note the **issuer URL**, **client id**,
  and **client secret** (OIDC), or the **metadata URL** (SAML).
- Decide which upstream attribute carries group membership (for example `groups`).

## Configure it

Federation is configured through the operator API, scoped to your org:

```bash
curl -X PUT https://<controlplane>/api/v1/orgs/<org>/idp \
  -H "Authorization: Bearer $DVX_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
        "type": "oidc",
        "name": "Corp SSO",
        "issuer": "https://accounts.example.com",
        "client_id": "daevix-web",
        "client_secret": "<your-client-secret>",
        "groups_attribute": "groups",
        "scopes": ["openid", "profile", "email", "groups"]
      }'
```

For a SAML IdP, send `"type": "saml"` with `"metadata_url"` instead of the OIDC
fields.

daevix drives the identity backend to create the org-scoped connection, enable
just-in-time account provisioning, and install the mapping that projects your
`groups_attribute` into `urn:dvx:groups`. The response echoes back only a
**reference** — type, name, group attribute, and status:

```json
{ "org_id": "acme", "type": "oidc", "name": "Corp SSO",
  "groups_attribute": "groups", "status": "configured" }
```

Read it back any time with `GET /api/v1/orgs/<org>/idp`, and remove federation
with `DELETE /api/v1/orgs/<org>/idp`.

## Your client secret is never stored by daevix

Secret custody is **pass-through**. The client secret you send flows straight to
the identity backend, which custodies it. daevix persists only the reference
above — there is no secret column in its database, so there is nothing to leak.
The secret never appears in any API response.

## Bind groups to roles

Once federation is live, an upstream group arrives as a `urn:dvx:groups` entry.
Grant a role or capability to that group with a group-scoped grant:

```bash
curl -X POST https://<controlplane>/api/v1/orgs/<org>/grants \
  -H "Authorization: Bearer $DVX_TOKEN" -H "Content-Type: application/json" \
  -d '{"principal":"group:<org>:<group>","role":"admin"}'
```

Everyone your IdP places in that group then holds the role in your org, with no
per-user administration on the daevix side.

## Cross-org isolation

An org's federation can only ever mint **that org's** group principals. Group
claims are namespaced by the caller's own org, so however your IdP names a group,
it becomes `group:<your-org>:<name>` — never another tenant's. One org's
federation can never grant authority in, or leak groups into, a sibling org.
