All notable changes to this project are documented here. The format is based on Keep a Changelog and this project adheres to Semantic Versioning.
[Unreleased]
[0.6.8] - 2026-06-01
Added
- Add host-configurable FAPI-oriented authorization-server controls:
:require_pushed_authorization_requestsrejects direct front-channel authorization requests unless they arrive through a PARrequest_uri, and:authorization_response_issincludes the RFC 9207issparameter on successful and error authorization responses. - Allow hosts to configure the advertised and accepted token endpoint client
authentication methods. The token endpoint and PAR endpoint now enforce
:token_endpoint_auth_methods_supportedwhen set, so deployments can expose stricter profiles such asprivate_key_jwtonly. - Advertise configured token endpoint authentication methods and PAR-required policy in OAuth/OIDC metadata.
[0.6.7] - 2026-06-01
Added
- Mount
POST /oauth/authorizealongsideGET /oauth/authorize, matching OpenID Connect Core's requirement that the Authorization Endpoint support both methods. - Extend the Ecto authorization-code store with successful-consumption markers
and issued-access-token tracking. When a successfully redeemed authorization
code is replayed, the token endpoint still returns
invalid_grantand now revokes the access token minted by the original code redemption when the Ecto store is configured.
[0.6.6] - 2026-06-01
Fixed
- Dynamic client registration now preserves inline
jwksmetadata (RFC 7591 §2) and hands it to the host:register_clientcallback. Hosts can then return those keys through:client_jwksfor request-object andprivate_key_jwtverification.
[0.6.5] - 2026-06-01
Fixed
- Return a clean
request_uri_not_supportedauthorization response for unsupported OIDCrequest_urireferences when no PAR store is configured, instead of calling a nil PAR store.
[0.6.4] - 2026-05-31
Changed
- Replace the direct
jasondependency with Elixir's built-inJSONmodule.
Added
- Add a test-only
req_dpopcompatibility check proving thatAttestoPhoenix.Plug.Authenticateaccepts RFC 9449 DPoP proofs generated by an external Req client plugin.req_dpopis not a runtime dependency. - Document
req_dpopas an optional Req client companion for tests and internal tooling.
[0.6.3] - 2026-05-31
Added
mix attesto_phoenix.install, an upgrade-aware Igniter installer. It is idempotent and re-runnable: it adds theAttestoPhoenix.Configconfig skeleton (issuer, keystore, repo, the Ecto-backed token stores, a chosen:oauth_path_prefix, and neutral defaults) to the host config, mountsattesto_routes/1at the chosen prefix into the host router, scaffolds host callback modules implementing the recommended behaviours (ClientStore,PrincipalStore,ScopePolicy,ConsentPolicy,RegistrationStore,EventSink) with documented stub callbacks, and points the host atmix attesto_phoenix.gen.migrationfor the Ecto tables.igniteris declared as an optional dependency, so the runtime package never forces it on consumers; the task is available to a host that opts into running it. Options:--oauth-path-prefixand--callbacks-module.Configurable OAuth endpoint paths.
AttestoPhoenix.Confignow accepts an:oauth_path_prefix(default"/oauth", reproducing the historic surface) plus explicit per-endpoint overrides (:authorize_path,:token_path,:par_path,:revocation_path,:registration_path,:userinfo_path) that win when set. Resolver helpers (token_endpoint_url/1,par_endpoint_url/1,revocation_endpoint_url/1,registration_endpoint_url/1,userinfo_endpoint_url/1,authorize_endpoint_url/1,jwks_uri/1,registration_client_uri/2, and the*_path/1helpers) build absolute URLs from the issuer and the resolved path. The discovery (RFC 8414), OpenID-configuration (OpenID Connect Discovery), and registration (RFC 7591 / RFC 7592) controllers read every advertised URL from these resolvers instead of hardcoding/oauth/*, andto_attesto_config/2passes the resolved token path to the core builder automatically so the DPoPhtufollows the mount. A host that mounts under/mcp/oauthnow advertises correct URLs.Named host-contract behaviours documenting the full callback contract with the governing RFC for each callback, as the recommended production shape:
AttestoPhoenix.ClientStore,AttestoPhoenix.PrincipalStore,AttestoPhoenix.ScopePolicy,AttestoPhoenix.ConsentPolicy,AttestoPhoenix.RegistrationStore, andAttestoPhoenix.EventSink. Wiring is unchanged: pass an anonymous function, a{module, function}pair, or a{module, function, extra_args}triple perAttestoPhoenix.Configkey.Dynamic registration metadata passthrough (RFC 7591 §2). The registration endpoint now validates and carries the known client-identity members (
client_name,client_uri,logo_uri,contacts,policy_uri,tos_uri, and related software/JWKS members) through to:register_clientso consent screens keep the client's identity. Unknown members are dropped and never promoted to trusted policy; known members are merged under the validated protocol-critical members so they cannot override them.Actionable
AttestoPhoenix.Config.new/1validation errors that name the callback/store/path to add for each enabled feature, and absolute-path validation for:oauth_path_prefixand the per-endpoint overrides.Operations guides wired into the published docs:
replay_nonce_production.md,proxy_canonical_host.md,error_envelope.md,consumer_migration.md, andexamples.md.
[0.6.2]
- Advertise
response_modes_supported: ["query"]from the RFC 8414 OAuth Authorization Server Metadata endpoint, matching the authorization-code redirect response mode already used by the Phoenix authorization endpoint.
[0.6.1]
- Emit
:token_deniedaudit/telemetry events for token endpoint failures, including OAuth error, status, client/grant/scope context when available, and sender-constraint presence. - Normalize Phoenix callback specs before handing
:cert_derto core Attesto protected-resource verification, so function captures,{Module, function}, and{Module, function, extra_args}all work consistently.
[0.6.0]
Initial release: a Phoenix/Ecto OAuth 2.0 / OIDC authorization server layer over attesto.
Added
AttestoPhoenix.Config: centralized, validated configuration with neutral host callbacks (:load_client,:verify_client_secret,:load_principal,:authorize_scope,:on_event, and others), deriving theAttesto.Configthe protocol layer consumes.AttestoPhoenix.Router: theattesto_routes/1macro mounting the token, revocation, discovery, JWKS, and optional dynamic-registration endpoints.- Controllers for the token endpoint (
authorization_code,refresh_token, andclient_credentialsgrants), revocation (RFC 7009), discovery (RFC 8414), JWKS (RFC 7517), and optional dynamic client registration (RFC 7591). AttestoPhoenix.Plug.AuthenticateandAttestoPhoenix.Plug.RequireScopesprotected-resource plugs with DPoP and mTLS sender-constraint enforcement.- Ecto-backed implementations of the attesto store behaviours: code store,
refresh store (rotation with reuse detection), DPoP nonce store, and DPoP
jtireplay check, plus an optional TTL sweeper. mix attesto_phoenix.gen.migrationto generate the operational tables.- Pushed Authorization Requests (PAR, RFC 9126),
private_key_jwtclient authentication, signed request object validation, token exchange, UserInfo, registration management cleanup, and Phoenix resource-server plugs.