## Where it comes from

In production, either the `SECRET_KEY_BASE` environment variable or the encrypted credentials, which
are themselves unlocked by `RAILS_MASTER_KEY`. One of the two has to be present or the app raises
during initialization.

```bash
bin/kamal app exec 'bin/rails runner "puts Rails.application.secret_key_base.present?"'
```

In development and test Rails generates and caches one for you, which is why you have never had to
think about it locally.

## What breaks when it changes

- **Every session.** Session cookies are signed with a derived key. A new base means existing cookies
  fail verification and are discarded, so everyone is signed out.
- **Signed URLs.** Active Storage URLs and any `signed_id` already issued stop verifying.
- **Encrypted cookies.** Anything stored in one is unreadable.

None of it is data loss. It is all re-derivable by signing in again. But doing it during business
hours means every user hits a sign-in screen at once, which for a passwordless app means every user
waits for an email.

## It is not the same as the master key

Two different things, often confused:

| Secret | Protects |
|---|---|
| `RAILS_MASTER_KEY` | Decrypts `config/credentials.yml.enc`. |
| `SECRET_KEY_BASE` | Derives signing and encryption keys at runtime. |

The master key can be used to store the secret key base, which is how most apps are set up, and is
why they look like one thing.

## Rotating it

There is no zero-downtime path for a single value, because there is no window where both are valid.
The practical approach is to deploy the change at a quiet hour and accept the sign-outs. Rails
supports rotation for cookies specifically, which can smooth it, but it is configuration you add
before you need it, not during.

## Do not commit it

`bin/check` runs a secret scan, so a key pasted into a tracked file fails the build. That check is
the reason this value has never needed rotating in this repository.
