# `Sake.Auth`
[🔗](https://github.com/hattoriai/sake/blob/v0.4.3/lib/sake/auth.ex#L1)

Authorization for a Sake endpoint: the host app is the OAuth 2.1
authorization server, and the endpoint is the resource server.

Configure it on the `Sake` child (see `Sake.child_spec/1`) and mount the
routes with `Sake.Router` (Phoenix) or `Sake.Auth.RouterPlug` (Plug).
An endpoint whose tokens come from another authorization server is
`Sake.Auth.External`'s instead.

## The public API

These modules are for host code; every other `Sake.Auth` module is
Sake's own and may change in any release:

  * `Sake.Auth` — the configuration, a person's grants, pruning.
  * `Sake.Auth.Config` — the `auth:` options.
  * `Sake.Auth.Subject` — the behaviour of the host's subject module.
  * `Sake.Auth.Consent` and `Sake.Auth.Consent.Default` — the consent
    and error pages.
  * `Sake.Auth.Store`, `Sake.Auth.Store.ETS`, `Sake.Auth.Store.Ecto`
    and `Sake.Auth.Migration` — where clients, codes, pushed
    authorization requests, device grants, tokens and consents live;
    `Sake.Auth.Code`, `Sake.Auth.PushedRequest` and
    `Sake.Auth.DeviceGrant` are the code, the pushed request and the
    device grant a store keeps.
  * `Sake.Auth.External` — an endpoint on another authorization server.
  * `Sake.Auth.TokenRecord` — the token of a request, in `ctx.token`.
  * `Sake.Auth.Client` and `Sake.Auth.Clients` — the registered clients.
  * `Sake.Auth.TrustedIssuer` — the issuers of JWT grants.
  * `Sake.Auth.Challenge` — a `WWW-Authenticate` challenge.
  * `Sake.Auth.WellKnown`, `Sake.Auth.Authorize`,
    `Sake.Auth.DeviceVerification` and `Sake.Auth.RouterPlug` — the
    endpoints a Plug host mounts itself.
  * `Sake.Client.Auth`, `Sake.Client.Auth.Browser`,
    `Sake.Client.Auth.Headless`, `Sake.Client.Auth.Device` and
    `Sake.Client.Auth.Store` — the client's `auth:` options.

Calls run one way: the rest of Sake calls these modules (and the
functions marked `@doc false` that say who calls them), and nothing in
`Sake.Auth` or `Sake.Client.Auth` calls the rest of Sake.

## Cores and adapters

For contributors: each endpoint is a core and an adapter, both under
`lib/sake/auth/`. The core is pure functions over the configuration and
plain data (a parameter map, header values, a principal); it may use
the store, and it never sees a `Plug.Conn`. The adapter is a thin plug
that parses the request, reads the signed-in person with
`c:Sake.Auth.Subject.from_conn/1` where one is involved, calls the
core, and renders JSON, a redirect or the consent page.

  * Authorization: `authorization_request.ex` validates a request
    (parameters a later endpoint adds go in its `extra`), and
    `grant.ex` decides once the person is known and issues the code;
    `Sake.Auth.Authorize` is the adapter, and keeps the consent form's
    signed request and CSRF token.
  * Tokens: `token_grants.ex`, whose `exchange/4` has one clause per
    grant type; `token.ex` is the adapter.
  * Pushed authorization requests (RFC 9126): `par.ex` validates and
    stores a pushed request as an authorization request, and takes it
    back for the authorize endpoint; `pushed_authorization.ex` (the
    client's push) is the adapter, and `Sake.Auth.Authorize` takes a
    `request_uri`.
  * Device authorization (RFC 8628): `device.ex` starts a device grant
    and takes the person's decision through `grant.ex`;
    `device_authorization.ex` (the client's request) and
    `Sake.Auth.DeviceVerification` (the page where the person enters
    the user code) are the adapters, and the token endpoint's device
    code clause issues the tokens.
  * Revocation and registration: `revocation.ex` and `registration.ex`;
    `revoke.ex` and `dcr.ex` are the adapters.
  * Metadata: `metadata.ex`, a base map and a list of contributors, one
    per feature; `Sake.Auth.WellKnown` is the adapter.
  * Access tokens: `bearer.ex` checks a request described as a map;
    `authenticate/2` in this module is its adapter.
  * How the person signed in (RFC 9470): `authentication.ex` holds the
    context (`acr`, `auth_time`), an authorization request's
    `acr_values` and `max_age`, and the check of one against the
    other, for the authorization server's adapters (which ask
    `c:Sake.Auth.Subject.authentication/1` and call
    `c:Sake.Auth.Subject.reauthenticate/2`) and for the components'
    `authentication:` requirements alike.
  * OpenID Connect: `signing_keys.ex` reads `signing_keys:` and builds
    the JWK Set, which `public_keys.ex` serves at `/jwks`;
    `id_token.ex` makes the ID token the token endpoint's grants add
    for `openid`; `claims.ex` is the userinfo endpoint, checking the
    token through `bearer.ex`, and `user_info.ex` its adapter, which
    renders a refusal as an OAuth error (RFC 6750) rather than
    JSON-RPC. `metadata.ex` builds the OpenID Provider metadata from
    the authorization server's, and `Sake.Auth.WellKnown` serves it.

A new endpoint is a core module and an adapter, a route in
`Sake.Router` and in `Sake.Auth.RouterPlug`, and a URL helper in
`Sake.Auth.Config` next to `authorize_url/1`; a new metadata field is a
contributor in `metadata.ex`. A test checks that no core module calls
`Plug.Conn`.

# `config`

```elixir
@spec config() :: Sake.Auth.Config.t()
```

# `list_grants`

```elixir
@spec list_grants(Sake.Auth.Config.t(), String.t()) :: [map()]
```

The active grants of a person: one entry per client, for a settings page.

# `prune`

```elixir
@spec prune(Sake.Auth.Config.t()) :: :ok
```

Deletes expired codes, device grants and tokens, the remembered
consents older than the refresh token lifetime that no live token
family still uses, and the dynamically registered clients that, `unused_client_ttl` seconds
(a day by default) after registering, hold no live token, consent,
code or device grant. Schedule it (a cron job, Oban, or a periodic task).

# `revoke_grant`

```elixir
@spec revoke_grant(Sake.Auth.Config.t(), String.t(), String.t()) :: :ok
```

Revokes every token of a client for a person, and forgets every consent of that client for the person.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
