Federate Enterprise Identity
Admit bearer tokens by key, discovery, or introspection, derive a stable subject for each enterprise principal, and read the identity context every session carries.
On this page
Put your identity provider in front of the MCP edge, and every session from one employee or workload acts as one Chio subject. Capabilities are issued against that subject, so receipts attribute work to the person or service behind the token.
The edge admits bearer tokens from an OIDC or OAuth 2.0 provider, canonicalizes the principal, and derives the subject from a persistent seed. The steps use an Azure AD tenant through OIDC discovery; pinned keys and token introspection follow the same path.
StartThe edge admits the token and names its principal
The edge verifies the bearer under a pinned key, against the provider's discovered JWKS, or through its introspection endpoint. It canonicalizes the principal as oidc:<issuer>#sub:<sub> and derives a stable Chio subject from it with the identity federation seed. Remote MCP Edge.
1. Choose how the edge verifies tokens
Pick one mode by the tokens your provider issues. JWT verification and introspection are exclusive.
| Mode | Flags | Verifies |
|---|---|---|
| Pinned key | --auth-jwt-public-key, --auth-jwt-issuer, --auth-jwt-audience | The JWT signature under one Ed25519 key, the issuer, the audience |
| Discovery | --auth-jwt-discovery-url, optional --auth-jwt-provider-profile | The JWT against the discovered JWKS |
| Introspection | --auth-introspection-url, --auth-introspection-client-id, --auth-introspection-client-secret | An opaque token through the provider's introspection endpoint |
Pass the introspection client id and secret together, and prefer CHIO_MCP_AUTH_INTROSPECTION_CLIENT_SECRET over the flag so the secret stays out of the process list. The edge refuses to boot with --auth-token beside any OAuth flag. Discovery fetches and introspection calls each time out after 5 seconds.
Before you begin
- An identity provider that issues JWTs or supports OAuth 2.0 token introspection.
- A policy file for the edge and a seed file for identity federation, kept outside source control. The seed must persist: a new seed derives new subjects.
2. Serve the edge with a federation seed
Give the admin API its own token, then start the edge with the discovery URL, the provider profile, the expected audience, and the seed file.
export CHIO_ADMIN_TOKEN="$(openssl rand -hex 32)"
DISCOVERY=https://login.microsoftonline.com/larkfield.example/v2.0/.well-known/openid-configuration
chio mcp serve-http \
--policy ./policy.yaml \
--server-id pricing \
--listen 127.0.0.1:8931 \
--auth-jwt-discovery-url "$DISCOVERY" \
--auth-jwt-provider-profile azure-ad \
--auth-jwt-audience chio-mcp \
--identity-federation-seed-file ./identity-federation.seed \
-- python mcp_server.pyYou should see the edge listening on 127.0.0.1:8931. JWT and introspection modes refuse to boot without CHIO_ADMIN_TOKEN. To share provider records with the trust service, add --enterprise-providers-file; Provider Registry & SCIM describes the records.
3. Read the canonical principal on a session
Connect a client with a token from your provider, then read its session through the admin API. The edge records the canonical principal and the derived subject in authContext.method.enterpriseIdentity.
curl -sS -H "Authorization: Bearer $CHIO_ADMIN_TOKEN" \
"http://127.0.0.1:8931/admin/sessions/$SESSION_ID/trust" \
| jq '.authContext.method.enterpriseIdentity | {federationMethod, principal, subjectKey}'{
"federationMethod": "jwt",
"principal": "oidc:https://login.microsoftonline.com/larkfield.example/v2.0#oid:4b1f…9e02",
"subjectKey": "7d3a…c1f8"
}You should see the principal in one of three forms, chosen by the claims the token carries:
oidc:<issuer>#sub:<sub>for a user principal with a subject claim.oidc:<issuer>#client:<client_id>for a client principal when the subject claim is absent.oidc:<issuer>#oid:<oid>for a user under the Azure AD profile, which triesoid, thensub, then falls back toazp,appid, orclient_idfor clients.
The full context carries the provider id and record id, the provider kind, the federation method (jwt, introspection, scim, or saml), the principal, the subject key, the tenant, organization, groups, and roles, the source of each attribute, and the trust material reference. Beside it, authContext.method.federatedClaims holds the raw clientId, objectId, tenantId, organizationId, groups, and roles.
4. Confirm that two sessions share one subject
Open a second session with a fresh token for the same person and read it the same way. You should see the same principal and the same subjectKey: the edge derives the subject from the seed and the principal, never from the session.
The capabilities in each trust response carry the same subjectPublicKey in both sessions. The receipts for each session's tool calls name those capabilities, and GET /admin/receipts/tools?capability_id=<id> lists them, so one person's work reads as one subject across every session they opened.
A refused token stops before any session exists
A request with no bearer, or a bearer that fails the configured key, issuer, or audience, receives HTTP 401, and the edge creates no session, capability, or subject for it. A token that verifies but carries none of the claims a principal form needs is refused the same way, with a reason such as JWT bearer token missing subject and client_id for identity federation.
Tokens that carry a cnf claim are sender-constrained, and the edge enforces the DPoP proof, mTLS thumbprint, or attestation digest the claim binds; Remote MCP Edge covers that profile. To revoke the capabilities already tracked for a user, deprovision the user through SCIM on the trust service.