Packages
attesto_phoenix
0.12.0
2.1.0
2.0.2
2.0.1
2.0.0
1.4.0
1.3.0
1.2.0
1.1.0
1.0.0
0.20.0
0.19.1
0.19.0
0.18.0
0.17.0
0.16.0
0.15.0
0.14.2
0.14.1
0.14.0
0.13.5
0.13.4
0.13.3
0.13.2
0.13.1
0.13.0
0.12.0
0.11.0
0.10.0
0.9.5
0.9.4
0.9.3
0.9.2
0.9.1
0.9.0
0.8.0
0.7.7
0.7.6
0.7.5
0.7.4
0.7.3
0.7.2
0.7.1
0.7.0
0.6.23
0.6.22
0.6.21
0.6.20
0.6.19
0.6.18
0.6.17
0.6.16
0.6.15
0.6.14
0.6.13
0.6.12
0.6.11
0.6.10
0.6.9
0.6.8
0.6.7
0.6.6
0.6.5
0.6.4
0.6.3
0.6.2
0.6.1
0.6.0
Phoenix/Ecto OAuth 2.0 / OIDC authorization server layer over attesto: authorization, token, PAR, revocation, discovery, JWKS, UserInfo, protected-resource plugs, and Ecto-backed token stores.
Current section
Files
Jump to
Current section
Files
guides/examples.md
# Example configurations
Two minimal `AttestoPhoenix.Config` setups. Both assume the host has wired the
router macro and a pipeline that installs the config on the connection.
## Confidential client (server-side app, client secret)
A confidential client authenticates with a secret at the token endpoint
(RFC 6749 §2.3.1). This config issues access and refresh tokens for the
authorization-code grant and serves discovery.
```elixir
AttestoPhoenix.Config.new(
issuer: "https://auth.example",
keystore: MyApp.Keystore,
repo: MyApp.Repo,
# Client registry (AttestoPhoenix.ClientStore).
load_client: &MyApp.AuthZ.load_client/1,
verify_client_secret: &MyApp.AuthZ.verify_client_secret/2,
client_id: &MyApp.AuthZ.client_id/1,
client_redirect_uris: &MyApp.AuthZ.client_redirect_uris/1,
client_public?: fn _client -> false end,
# Subject (AttestoPhoenix.PrincipalStore).
load_principal: &MyApp.AuthZ.load_principal/1,
build_principal: &MyApp.AuthZ.build_principal/3,
# Login + consent (AttestoPhoenix.ConsentPolicy).
authenticate_resource_owner: &MyApp.AuthZ.authenticate_resource_owner/3,
consent: &MyApp.AuthZ.consent/3,
# Scope policy (AttestoPhoenix.ScopePolicy); omit to default to
# "subset of :scopes_supported".
authorize_scope: &MyApp.AuthZ.authorize_scope/2,
scopes_supported: ["openid", "profile", "email"],
# Shared production token stores.
code_store: AttestoPhoenix.Store.EctoCodeStore,
refresh_store: AttestoPhoenix.Store.EctoRefreshStore,
replay_check: &AttestoPhoenix.Store.EctoReplayCheck.check_and_record/2,
nonce_store: AttestoPhoenix.Store.EctoNonceStore,
sweep_interval_ms: 60_000
)
```
## Public PKCE client (native / SPA, no secret)
A public client holds no secret and proves possession of the authorization
code with PKCE (RFC 7636). It authenticates at the token endpoint with
`none`.
```elixir
AttestoPhoenix.Config.new(
issuer: "https://auth.example",
keystore: MyApp.Keystore,
repo: MyApp.Repo,
load_client: &MyApp.AuthZ.load_client/1,
# A public client presents no secret; verification always fails closed if a
# secret is somehow presented.
verify_client_secret: fn _client, _secret -> false end,
client_id: &MyApp.AuthZ.client_id/1,
client_redirect_uris: &MyApp.AuthZ.client_redirect_uris/1,
client_public?: fn _client -> true end,
load_principal: &MyApp.AuthZ.load_principal/1,
build_principal: &MyApp.AuthZ.build_principal/3,
authenticate_resource_owner: &MyApp.AuthZ.authenticate_resource_owner/3,
# require_pkce defaults to true; PKCE is enforced for the code grant.
scopes_supported: ["openid", "profile"],
code_store: AttestoPhoenix.Store.EctoCodeStore,
refresh_store: AttestoPhoenix.Store.EctoRefreshStore,
replay_check: &AttestoPhoenix.Store.EctoReplayCheck.check_and_record/2,
nonce_store: AttestoPhoenix.Store.EctoNonceStore,
sweep_interval_ms: 60_000
)
```
## Mounting somewhere other than `/oauth`
Both configs above advertise the historic `/oauth/*` endpoints. To advertise a
different mount (for example `/mcp/oauth`), add a single key:
```elixir
oauth_path_prefix: "/mcp/oauth"
```
See `guides/consumer_migration.md` for the details.