# `PhoenixKit.API.Keys.Cache`
[🔗](https://github.com/BeamLabEU/phoenix_kit/blob/v2.64.1/lib/phoenix_kit/api/keys/cache.ex#L1)

A 60 second cache of API key rows, keyed by token prefix.

Verifying a key on every request would otherwise cost a query per call. The
cached row carries the owner uuid, scopes, flags, IP allow-list, expiry and
revocation time. **Owner rights are never cached**: they are computed on every
request (`PhoenixKit.API.Keys.effective_scopes/1`), so blocking, deleting or
demoting the owner takes effect on the next request even while the row is
cached.

The rows live in a `PhoenixKit.Cache` instance named `:api_keys`, which
`PhoenixKit.Supervisor` starts. Changing a key (revoke, rotate) calls
`invalidate/1`, which drops the row on this node at once and broadcasts the
prefix over PubSub; this module is also a small process that listens for those
broadcasts and drops the row on the other nodes. Without the cache process
`fetch/2` simply reads the database every time.

`touch_last_used?/1` answers whether `last_used_at` may be written now, at
most once per minute per key.

# `child_spec`

Returns a specification to start this module under a supervisor.

See `Supervisor`.

# `fetch`

```elixir
@spec fetch(String.t(), (-&gt; struct() | nil)) :: struct() | nil
```

Returns the key row for `prefix`, from the cache or from `loader`.

A `nil` from `loader` is returned as `nil` and is **not** cached, so a key
created a moment after a failed lookup is found at once.

# `invalidate`

```elixir
@spec invalidate(String.t()) :: :ok
```

Forgets the row for `prefix` on this node and tells the other nodes to do so.

Never raises: a missing cache or PubSub is logged by the layer below and the
row then expires on its own within 60 seconds.

# `touch_last_used?`

```elixir
@spec touch_last_used?(String.t()) :: boolean()
```

Whether `last_used_at` of this key may be written now.

True at most once per minute per key on this node.

---

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