Skip to content

feat(federation): add automatic client registration (OpenID Federation 1.0 §12.1) - #259

Merged
osanderson merged 1 commit into
mainfrom
federation-automatic-registration
Sep 10, 2026
Merged

feat(federation): add automatic client registration (OpenID Federation 1.0 §12.1)#259
osanderson merged 1 commit into
mainfrom
federation-automatic-registration

Conversation

@osanderson

Copy link
Copy Markdown
Collaborator

Summary

  • Adds AutomaticClientRepository (storage.ClientRepository) and AutomaticClientKeySource (keys.ClientKeySource) implementing OpenID Federation 1.0 §12.1 "Automatic Registration": an OP can accept a Relying Party's own Entity Identifier as client_id with no prior registration step. On a miss from an existing (static) repository, the RP's Trust Chain is resolved via Resolver, and its Resolved Metadata's own openid_relying_party object becomes the client's registration.
  • Resolutions are cached per client, bounded by both a configured max age and the chain's own natural ResolvedEntity.ExpiresAt — never trusted longer than the chain itself remains valid.
  • Static registration always wins: both types try their own Underlying dependency first, and the two share one resolution/cache so a single request touching both ResolveClient and ResolveVerificationKeys for the same client only resolves its chain once.
  • The client's authentication key is read from its own openid_relying_party metadata's jwks — never from its Entity Configuration's own top-level federation signing key, a distinct key for a distinct purpose per federation/doc.go. A dedicated test confirms AutomaticClientKeySource resolves the right one.

Deliberately out of scope for this first version (documented in doc.go and AutomaticClientRepository's own comment)

  • Only ClientAuthMethodPrivateKeyJWT — every RFC 8705 mTLS method needs the x5c member of the client's own JWK, which this module's JOSE layer doesn't currently preserve.
  • Only an inline jwks object — jwks_uri (a remote fetch) isn't supported yet.
  • No CIBA, no client_credentials for automatically-registered clients.
  • No request_uri/JAR/PAR-level enforcement of §12.1.1's own aud/sub/jti Request Object rules — that's request-handling, not client registration, and is left for a later change.
  • Explicit Registration (§12.2) is not implemented at all.

Test plan

  • go build ./...
  • go test -race ./...
  • golangci-lint run ./... — 0 issues
  • New tests: metadata→RegisteredClientConfig mapping (valid + every rejection path, algorithm/encryption pairing), constructor validation for both types, static-registration-wins precedence for both, federation fallback end-to-end over real HTTPS test servers (a genuine two-level TA→RP chain), cache-hit call-counting (the RP's own well-known endpoint is fetched exactly once across two calls within the cache window), and the OIDC-key-vs-federation-key distinction.
  • federation package coverage: 98.2%

🤖 Generated with Claude Code

https://claude.ai/code/session_017N2kkxv9BR4Qmj8De3Ucs6

…n 1.0 §12.1)

Adds AutomaticClientRepository (storage.ClientRepository) and
AutomaticClientKeySource (keys.ClientKeySource): an OpenID Provider can
accept a Relying Party's own Entity Identifier as client_id with no
prior registration step. On a miss from an existing (static) repository,
the RP's Trust Chain is resolved via Resolver, and its Resolved
Metadata's own openid_relying_party object becomes the client's
registration — cached per client, bounded by both a configured max age
and the chain's own natural ResolvedEntity.ExpiresAt.

Static registration always wins (both types try their own Underlying
first), and the two share one resolution/cache so a request touching
both ResolveClient and ResolveVerificationKeys for the same client only
resolves its chain once.

First version deliberately narrow (documented in doc.go and
AutomaticClientRepository's own comment): only
ClientAuthMethodPrivateKeyJWT (every RFC 8705 mTLS method needs "x5c"
from the client's own JWK, which this module's JOSE layer doesn't yet
preserve), only an inline "jwks" (no jwks_uri), no CIBA or
client_credentials, and no request_uri/JAR/PAR-level enforcement of
§12.1.1's own aud/sub/jti Request Object rules (a request-handling
concern for a later change, not a client registration one).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017N2kkxv9BR4Qmj8De3Ucs6
@codecov

codecov Bot commented Sep 10, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 98.43750% with 2 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
federation/automatic_registration.go 98.43% 1 Missing and 1 partial ⚠️

📢 Thoughts on this report? Let us know!

@sonarqubecloud

Copy link
Copy Markdown

@osanderson
osanderson merged commit db360ab into main Sep 10, 2026
9 checks passed
@osanderson
osanderson deleted the federation-automatic-registration branch September 10, 2026 17:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant