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

Keeps a client's tokens and dynamic registrations across sessions. Pass
`store: {module, arg}` in `Sake.Client.connect/2`'s `auth:` options;
`arg` is handed to every callback.

Three kinds of keys:

  * `{:token, url}` — the token for one MCP endpoint (its canonical URL),
    with its refresh token, expiry, scopes, and the authorization server
    and client it was issued by and to.
  * `{:client, issuer}` — a dynamic registration (client id and secret)
    with one authorization server. Registrations are bound to their
    server: one is never presented to another.
  * `{:idp, issuer}` — the enterprise identity provider's refresh token
    from a SAML exchange (`grant: :enterprise` with `saml_assertion:`),
    with its expiry and the client at the provider it was issued to. It
    stands for the person's single sign-on until it expires: guard it
    like the tokens.

Values are maps with string keys and JSON values, so a store can write
them as JSON. They hold credentials: keep them where only the person
running the client can read them (OAuth 2.1 §7.1), such as the system
keychain or a file only they can read.

    defmodule MyApp.TokenStore do
      @behaviour Sake.Client.Auth.Store

      @impl true
      def fetch(dir, key) do
        case File.read(path(dir, key)) do
          {:ok, json} -> {:ok, JSON.decode!(json)}
          {:error, _} -> :error
        end
      end

      @impl true
      def put(dir, key, value) do
        File.write!(path(dir, key), JSON.encode!(value))
        File.chmod!(path(dir, key), 0o600)
      end

      defp path(dir, key),
        do: Path.join(dir, Base.url_encode64(:erlang.term_to_binary(key), padding: false))
    end

# `key`

```elixir
@type key() ::
  {:token, url :: String.t()}
  | {:client, issuer :: String.t()}
  | {:idp, issuer :: String.t()}
```

# `fetch`

```elixir
@callback fetch(arg :: term(), key()) :: {:ok, map()} | :error
```

# `put`

```elixir
@callback put(arg :: term(), key(), map()) :: :ok
```

---

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