Skip to main content
Version: v0.25.0 (Latest)

Accept federation clients on the authorization server

A hosted authorization server can onboard relying parties that nobody registered in advance, as long as they belong to a federation the server trusts. Instead of a registration record created by an administrator, the client proves who it is with its Trust Chain, and its keys and metadata come from that chain. The EDK implements both methods of OpenID Federation for OpenID Connect 1.1: Automatic Registration (§12.1), where the client registers implicitly with its first request, and Explicit Registration (§12.2), where it registers first and gets a signed registration response.

This guide is written for the operator of the hosted authorization server, and describes what the client has to send so you can support relying parties that integrate with it.

Some boundaries up front. This is not RFC 7591 dynamic client registration, which the hosted server does not offer. It is unrelated to the upstream sign-in bindings in Hosted sign-in and external federation. And it works in one direction only: the hosted authorization server accepts federation clients. The platform does not act as a federation relying party that registers itself at external OpenID Providers.

Enable federation clients​

Two things have to be in place: a Trust Domain decision about which federations the server accepts, and a federation entity for the server so relying parties can find and verify it.

Choose the accepted Trust Anchors​

The accepted federations are decided by a Trust Domain, through the Trust Domain API under /api/trust-domain/v1:

  1. Create a domain for the federations you accept (createTrustDomain, POST /domains).
  2. Add each federation's Trust Anchor as an anchor with evidence mechanism OIDFED_ENTITY, whose public identifier is the anchor's Entity Identifier (createTrustAnchor, POST /domains/{domainId}/anchors).
  3. Admit each anchor with the admission class CLIENT (putTrustAnchorAdmission, PUT /domains/{domainId}/anchors/{anchorId}/admissions/CLIENT). This admission class accepts only OIDFED_ENTITY anchors.
  4. Attach the domain to the authorization server for the usage CLIENT_REGISTRATION_TRUST (putTrustAttachment, PUT /attachments/AS/{authorizationServerId}/CLIENT_REGISTRATION_TRUST), where authorizationServerId is the server's resource UUID.

The anchors' keys are never configured here. Whenever a client's chain is verified, each anchor's keys are read from the anchor's own Entity Configuration. Without an attachment, or with an attachment whose domains hold no admitted federation anchors, the server accepts no federation clients at all. Trust domains explains anchors, admissions and attachments in general.

Publish the server as a federation entity​

Relying parties discover an OpenID Provider through its Entity Configuration, and they need a Trust Chain for it too. Give the server a federation entity as described in Join an existing federation:

  • use the server's issuer URL as the Entity Identifier. Request Objects must name exactly the server's issuer as audience, and relying parties address the audience by the provider's Entity Identifier, so the two have to be the same;
  • bind the server with an AUTHORIZATION_SERVER binding and declare the openid_provider role for an OpenID Provider, or oauth_authorization_server for a plain OAuth 2.0 server;
  • create and select a Federation Entity Key, have the federation's superior admit the entity, and publish it.

When the CLIENT_REGISTRATION_TRUST attachment exists, the published Entity Configuration adds three claims to the server's openid_provider or oauth_authorization_server metadata (OpenID Federation for OpenID Connect 1.1 §5.1.1):

  • client_registration_types_supported with automatic and explicit;
  • federation_registration_endpoint, which is <server Entity Identifier>/federation_registration;
  • request_authentication_methods_supported, stating that the Pushed Authorization Request endpoint takes private_key_jwt.

The claims follow the attachment at the moment of publication. After you create or delete the attachment, publish the server's entity again so its Entity Configuration says what the server does.

Automatic Registration​

With Automatic Registration the relying party skips a registration step and starts with an authorization request. End to end:

  1. The relying party resolves the server's Entity Configuration and Trust Chain, and learns that automatic registration is supported and that the Pushed Authorization Request endpoint expects private_key_jwt.
  2. It builds a Request Object with its own Entity Identifier as client_id, signed with a key from the jwks of its openid_relying_party metadata as published in the federation. The Request Object names only the server's issuer in aud, carries a fresh jti and an exp, and contains no sub. It includes a PKCE code_challenge.
  3. It sends the Request Object to the server's Pushed Authorization Request endpoint, authenticating with a private_key_jwt client assertion signed with the same key set.
  4. The server sees an https client_id it has no record of. It reads the anchors admitted for CLIENT_REGISTRATION_TRUST, resolves the client's Trust Chain from the client's Entity Configuration through its authority_hints to one of those anchors, verifies it, and applies the metadata policies of every superior in the chain. The client's registration is taken from the resolved openid_relying_party metadata and the signing keys it publishes.
  5. With that registration the server verifies the client assertion and the Request Object exactly as for any other client. A Request Object whose jti was already used is refused.
  6. The server returns a request_uri. The flow continues with the authorization request, and the token request authenticates with private_key_jwt again and presents the PKCE verifier.

A client registered this way is confidential and never receives a secret. It authenticates only with private_key_jwt, must use Pushed Authorization Requests and PKCE, and each Request Object is accepted once. Its resolved metadata must contain at least one redirect_uri; grant_types defaults to authorization_code and response_types to code. Automatic Registration always uses the OpenID Connect profile, so the client's metadata has to be openid_relying_party.

There is no stored registration record. The server keeps the resolved registration until the Trust Chain expires and resolves it again on the next request after that. A change to the accepted anchors takes effect for the next request.

When resolution fails, the client is treated as an unknown client and the Pushed Authorization Request is refused with the server's usual client error. The federation reason is not returned to the client; it is written to the server log with the client's Entity Identifier. Typical reasons are a chain that ends at an anchor that is not admitted, an expired statement somewhere in the chain, metadata that a superior's policy rejects, and missing redirect_uris.

Explicit Registration​

With Explicit Registration the relying party registers before it sends any authorization request.

The request​

The client sends POST <server Entity Identifier>/federation_registration with one of two bodies:

  • its Entity Configuration, as application/entity-statement+jwt. It may carry its Trust Chain in a trust_chain JWS header, and then optionally the server's chain in a peer_trust_chain header;
  • its Trust Chain, as application/trust-chain+json: a JSON array whose first element is its Entity Configuration. In this form neither header may be used.

The Entity Configuration used as a request differs from the one the client serves at its well-known URL in one way: its aud is exactly the server's Entity Identifier. Its iss and sub are both the client's https Entity Identifier, it lists authority_hints, its metadata contains openid_relying_party (or oauth_client when the server's binding declares no openid_provider role), and it is signed with a key from its own jwks.

What the server verifies​

The server identifies itself from the host and path the request was sent to, and refuses the request when no federation entity bound to a hosted authorization server lives at that URL. It then verifies the request against the anchors admitted for CLIENT_REGISTRATION_TRUST:

  • the request is a well-formed, unexpired Entity Statement with the claims above, signed with a key from its own jwks;
  • the Trust Chain, taken from the body or header or otherwise resolved from the authority_hints, verifies to one of the admitted anchors;
  • the chain continues at one of the request's authority_hints, and that Immediate Superior's statement lists the key that signed the request, so the request verifies with a key the superior vouches for;
  • after applying the metadata policies of the chain, client metadata of the expected Entity Type remains;
  • a peer_trust_chain, when sent, verifies and ends at the same anchor as the client's chain.

The registration itself is then checked. The client must authenticate with private_key_jwt, which is assumed when token_endpoint_auth_method is absent, so its metadata needs jwks or jwks_uri. An authorization_code client needs redirect_uris. Unknown grant or response types are refused.

The response​

The server stores the registration with the client's Entity Identifier as client_id and answers with a registration response signed by its selected Federation Entity Key, as application/explicit-registration-response+jwt. The response repeats the registered metadata and the client_id, and its expiry is the registration's expiry: the earlier of the Trust Chain's expiry and the request's exp. The registered client is confidential, has no secret and must use PKCE. Pushed Authorization Requests are not forced for explicitly registered clients unless the server requires them for every client.

A new registration from the same client replaces the earlier one, so a client renews by registering again before its registration expires. After expiry the registration can no longer be used. If the response cannot be signed, for example because the server's entity has no selected key, the registration is withdrawn again and the client receives a server error.

Errors​

Errors are returned as JSON with error and error_description:

StatuserrorCause
404not_foundNo federation entity bound to a hosted authorization server at this URL.
403invalid_trust_anchorThe server accepts no federation clients: no admitted anchors for CLIENT_REGISTRATION_TRUST.
400invalid_requestWrong content type, empty body, or a request that is malformed, not addressed to this server, or not signed with a key the superior vouches for.
400invalid_trust_anchor, invalid_trust_chainThe chain does not reach an admitted anchor, does not verify, or has expired.
400invalid_metadataNo client metadata of the expected Entity Type remains after the chain's policies.
400invalid_client_metadataThe metadata cannot be registered: another authentication method, no keys, no redirect_uris, an unknown grant or response type.
500server_errorThe registration could not be stored or the response could not be signed.

Expiry, renewal and key rollover​

A federation client's registration never outlives its Trust Chain, and a chain is only as long-lived as its shortest statement. When the client's superior stops renewing its statement, or an anchor loses its CLIENT admission, the client loses access within one statement lifetime: Automatic clients at the next resolution, Explicit clients at the latest when their registration expires. To cut an explicitly registered client off earlier, remove its client registration in the server's client administration.

Clients rotate keys the federation way. The client publishes the new key next to the old one, its superior signs a statement that includes the new key, and only then does the client start signing with it. An Automatic client's resolved keys are refreshed when its chain is resolved again, so a client that switches keys too early is refused until then. An Explicit client registers again after the rollover.

The server's own keys follow the same rule. Explicit responses are signed with the key currently selected for the server's entity; create a new key, have the superior include it, select it and publish the entity again, then revoke the old key once no published statement depends on it.

Where it runs​

Federation registration runs in the enterprise tenant authorization server and platform services, which both connect to the OpenID Federation database. The monolith does not include it. See Deploy OpenID Federation.