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

Clients the host registers itself (for its own CLIs or partners).

    {:ok, client, secret} = Sake.Auth.Clients.create(Sake.Auth.config(), %{name: "Ops CLI", redirect_uris: ["http://127.0.0.1:8765/callback"]})

`confidential: true` returns a secret once; store it where the client
can read it. `scopes:` limits what the client may request.

A machine client — a service that calls your endpoint as itself, with
the client credentials grant — needs no redirect URI, and must be able
to authenticate: with a secret, or with a key it holds (`jwks:`, a JWK
Set of its public keys, or `jwks_uri:`, where to fetch them; the
client then signs a JWT for each token request, `private_key_jwt`).
Keys need the optional `jose` dependency.

    {:ok, client, nil} =
      Sake.Auth.Clients.create(config, %{
        name: "Nightly report",
        grant_types: ["client_credentials"],
        jwks: %{"keys" => [public_jwk]},
        scopes: ["reports:read"]
      })

`grant_types:` (default `["authorization_code", "refresh_token"]`) may
also list `"client_credentials"` (with the subject module's
`c:Sake.Auth.Subject.client_principal/1`) and
`"urn:ietf:params:oauth:grant-type:jwt-bearer"`, for grants from a
`Sake.Auth.TrustedIssuer`, and
`"urn:ietf:params:oauth:grant-type:device_code"`, for a CLI or a
device with no browser (with `device:` in the auth config); a client
without `"authorization_code"` needs no redirect URI.

`dpop_bound_access_tokens: true` (RFC 9449 §5.2) refuses the client's
token requests that carry no DPoP proof, so all its tokens are bound
to a key it holds.

`require_pushed_authorization_requests: true` (RFC 9126 §6), with
`par:` in the auth config, refuses the client's authorization requests
that it did not push first.

# `create`

```elixir
@spec create(Sake.Auth.Config.t(), map()) ::
  {:ok, Sake.Auth.Client.t(), String.t() | nil} | {:error, map()}
```

# `delete`

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

# `get`

```elixir
@spec get(Sake.Auth.Config.t(), String.t()) :: {:ok, Sake.Auth.Client.t()} | :error
```

# `list`

```elixir
@spec list(Sake.Auth.Config.t()) :: [Sake.Auth.Client.t()]
```

# `resolve`

```elixir
@spec resolve(Sake.Auth.Config.t(), term()) ::
  {:ok, Sake.Auth.Client.t()}
  | {:error, :invalid_client | :not_allowed | :unreachable | :invalid_document}
```

Finds a client by id: a CIMD URL is fetched, anything else is looked up in the store.

---

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