AttestoPhoenix (AttestoPhoenix v0.6.1)

Copy Markdown View Source

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

See the README for the supply/own breakdown, the router and plug usage, and the migration generator.