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.5] - 2026-06-01

Fixed

  • Return a clean request_uri_not_supported authorization response for unsupported OIDC request_uri references when no PAR store is configured, instead of calling a nil PAR store.

[0.6.4] - 2026-05-31

Changed

  • Replace the direct jason dependency with Elixir's built-in JSON module.

Added

  • Add a test-only req_dpop compatibility check proving that AttestoPhoenix.Plug.Authenticate accepts RFC 9449 DPoP proofs generated by an external Req client plugin. req_dpop is not a runtime dependency.
  • Document req_dpop as 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 the AttestoPhoenix.Config config skeleton (issuer, keystore, repo, the Ecto-backed token stores, a chosen :oauth_path_prefix, and neutral defaults) to the host config, mounts attesto_routes/1 at 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 at mix attesto_phoenix.gen.migration for the Ecto tables. igniter is 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-prefix and --callbacks-module.

  • Configurable OAuth endpoint paths. AttestoPhoenix.Config now 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/1 helpers) 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/*, and to_attesto_config/2 passes the resolved token path to the core builder automatically so the DPoP htu follows the mount. A host that mounts under /mcp/oauth now 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, and AttestoPhoenix.EventSink. Wiring is unchanged: pass an anonymous function, a {module, function} pair, or a {module, function, extra_args} triple per AttestoPhoenix.Config key.

  • 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_client so 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/1 validation errors that name the callback/store/path to add for each enabled feature, and absolute-path validation for :oauth_path_prefix and 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, and examples.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_denied audit/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_der to 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 the Attesto.Config the protocol layer consumes.
  • AttestoPhoenix.Router: the attesto_routes/1 macro mounting the token, revocation, discovery, JWKS, and optional dynamic-registration endpoints.
  • Controllers for the token endpoint (authorization_code, refresh_token, and client_credentials grants), revocation (RFC 7009), discovery (RFC 8414), JWKS (RFC 7517), and optional dynamic client registration (RFC 7591).
  • AttestoPhoenix.Plug.Authenticate and AttestoPhoenix.Plug.RequireScopes protected-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 jti replay check, plus an optional TTL sweeper.
  • mix attesto_phoenix.gen.migration to generate the operational tables.
  • Pushed Authorization Requests (PAR, RFC 9126), private_key_jwt client authentication, signed request object validation, token exchange, UserInfo, registration management cleanup, and Phoenix resource-server plugs.