defmodule AttestoPhoenix do @moduledoc """ A Phoenix/Ecto OAuth 2.0 / OIDC authorization-server and resource-server layer built on top of `Attesto`. `Attesto` is transport-agnostic: it implements the pure, effect-free protocol primitives - JWT mint/verify with per-key algorithm metadata (RFC 7519), DPoP sender-constraint proofs (RFC 9449), mutual-TLS binding (RFC 8705), PKCE (RFC 7636), the JWK Set (RFC 7517), authorization-server metadata (RFC 8414), `private_key_jwt` client assertions (RFC 7523), signed request objects (RFC 9101), and the scope grant-form algebra. It deliberately carries no HTTP, no persistence, and no identity model. `attesto_phoenix` adds exactly the two things a running server needs and the core leaves out: a transport (HTTP endpoints and protected-resource plugs) and persistence (Ecto-backed implementations of the core store behaviours). Everything that is inherently application policy stays the host's, supplied through a small set of neutral configuration callbacks. ## The split The library keeps the same boundary `Attesto` draws - *protocol* versus *policy* - and adds a third concern, *transport*: * **Protocol (core).** `Attesto.Token`, `Attesto.DPoP`, `Attesto.MTLS`, `Attesto.PKCE`, `Attesto.Scope`, `Attesto.JWKS`, `Attesto.ClientAssertion`, `Attesto.RequestObject`, and `Attesto.Discovery`. Pure functions over bytes and claims. This layer is reused verbatim; this package adds no crypto and forwards every protocol decision to it. * **Transport (here).** Controllers behind a router macro that mount authorization, token, pushed-authorization-request (RFC 9126), revocation (RFC 7009), discovery (RFC 8414), JWK Set (RFC 7517), UserInfo, and optional dynamic-registration (RFC 7591) endpoints, plus protected-resource plugs that verify a Bearer/DPoP access token and enforce its sender-constraint binding. The controllers and plugs use the core OAuth-error / `WWW-Authenticate` helpers so every failure is an RFC 6749 §5.2 / RFC 6750 §3 response, never a silent reject. * **Persistence (here).** Ecto schemas that implement the core store behaviours for authorization codes and refresh tokens, and - for clustered correctness - DPoP nonces and proof `jti` replay records. Migration scaffolding is a `mix` generator that writes the migration into the host application; this package owns no migration of its own. * **Policy (host application).** The client registry and its revocation rule, client-secret hashing, the subject/principal model, the scope catalog, signing keys, and the audit log. These are injected as the callbacks documented on `AttestoPhoenix.Config`, so the library never hardcodes one application's identity model. ## Configuration All behaviour is centralized in `AttestoPhoenix.Config`. It is the single source of truth read by every controller and plug: it validates the required keys at build time (raising `ArgumentError` so misconfiguration fails closed at boot), applies neutral defaults, and derives the `Attesto.Config` the protocol layer runs against via `AttestoPhoenix.Config.to_attesto_config/2`. Anything that is application policy is a callback rather than a baked-in assumption, named in OAuth terms: * client lookup -> `:load_client` * client-secret verification -> `:verify_client_secret` * client public keys -> `:client_jwks` * subject/principal resolution -> `:load_principal` * scope catalog / narrowing -> `:scopes_supported` and/or `:authorize_scope` * audit / telemetry -> `:on_event` (optional, no-op by default) * dynamic client persistence -> `:register_client` (only when registration is enabled) * mTLS certificate extraction -> `:cert_der` (only when mTLS is enabled) * HTTPS / proxy trust -> `:require_https` and `:trusted_proxies` See `AttestoPhoenix.Config` for the full key reference and the default for each value. ## Mounting the routes `AttestoPhoenix.Router` provides the `attesto_routes/1` macro, which mounts the authorization-server endpoints under a scope the host chooses. Discovery and the JWK Set are public; the token and revocation endpoints authenticate the client via the `:load_client` / `:verify_client_secret` callbacks. ## Entry points * `AttestoPhoenix.Config` - the validated configuration every controller and plug reads, and the derivation of the protocol `Attesto.Config`. * `AttestoPhoenix.Router` - the `attesto_routes/1` macro that mounts the HTTP surface. See the `README` for the supply/own breakdown, the router and plug usage, and the migration generator. """ end