# `PhoenixKit.Integrations.KeyStore.Chain`
[🔗](https://github.com/BeamLabEU/phoenix_kit/blob/v2.14.2/lib/phoenix_kit/integrations/key_store/chain.ex#L1)

Keeps the encryption secret in more than one place at once.

This is what makes a remote store an *addition* rather than a foundation.
Configure the local file first and something remote second, and the secret is
written to both while every read is served by the local one:

    config :phoenix_kit,
      integrations_key_store:
        {PhoenixKit.Integrations.KeyStore.Chain,
         stores: [
           PhoenixKit.Integrations.KeyStore.File,
           {PhoenixKit.Integrations.KeyStore.S3, bucket: "my-ops-bucket"}
         ]}

A PhoenixKit install that wants nothing remote configures nothing and loses
nothing: the file store on its own remains the default and the whole feature
is opt-in. Requiring an AWS account before someone can use integrations at all
would be the wrong shape, and this is the shape that avoids it.

## Reading

The first store that has the secret answers. A later store answering when an
earlier one did not is the recovery case — the local file was lost and the
remote copy saved it — so it is reported at `:warning` rather than passing
silently: the operator should know the primary is empty before the remote one
is also gone.

## Writing

Every store is written, and the read-back verification in
`PhoenixKit.Integrations.KeyStore.write_verified/1` then checks the chain,
which by definition checks the first store. A failure in **any** store is
reported: a backup that quietly stopped being written is not a backup, and
finding out during a recovery is finding out too late.

## What this deliberately does not do

It does not fall back to a later store on *write* failure, and it does not
hide a partial success behind an `:ok`. Both would produce the single
situation this whole area exists to prevent — believing the secret is safe
somewhere it is not.

# `stores`

```elixir
@spec stores(keyword()) :: [{module(), keyword()}]
```

The configured members, normalised to `{module, opts}`.

An empty chain is a configuration mistake, not a working "store nothing"
state, and the callbacks above report it as such rather than pretending to
have saved something.

---

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