Secrets and backups
what is encrypted, and how to recover.
What ADMIN_SECRET_KEY protects, what happens if you lose or change it, how to recover, and what to back up on a Node server or on Vercel with Postgres.
01What ADMIN_SECRET_KEY encrypts
The commands on this page are written for the shell of macOS and Linux (bash or zsh). On Windows, run them in WSL (Windows Subsystem for Linux, Ubuntu) or Git Bash: commands such as cp, openssl, set -a && . ./.env and multi-line curl with \ do not work as written in PowerShell or cmd. The node and pnpm commands work in any of them.
ADMIN_SECRET_KEY is a 32-byte key (64 hex characters, or base64) that you set in the environment. It is never stored in the database. The Admin Kit uses it to encrypt the secrets you save in the console before they reach storage (packages/admin-kit/server/crypto.ts):
| Stored value | How it is protected |
|---|---|
| Anthropic API key saved under Integrations | Encrypted: AES-256-GCM, a fresh random 12-byte IV for every save, the setting's name bound as associated data (a ciphertext cannot be moved to another field). Write-only in the console: it can be replaced or tested, never read back. |
| Webhook signing secret (Notifications) | Encrypted the same way. |
| Each member's two-factor (authenticator) secret | Encrypted the same way. |
| Passwords | Not encrypted but hashed with scrypt and a per-user salt. They do not depend on ADMIN_SECRET_KEY. |
| Sign-in sessions, setup codes, two-factor recovery codes | Only a SHA-256 hash is stored; ADMIN_SETUP_TOKEN is compared by its SHA-256 hash in constant time and is never stored. They do not depend on ADMIN_SECRET_KEY. |
| Pro plan sign-in cookies (users' browsers) | Signed with a key derived from ADMIN_SECRET_KEY (server/app.ts); nothing is stored on the server. |
| Ordinary settings, including the builder and pay-to addresses | Stored as plain values; addresses are masked in the console, the audit log and history. Only the owner can reveal one. |
An ANTHROPIC_API_KEY set in the environment is not stored at all; it stays in your host's environment settings.
Encrypted rows live in the secrets table (SQLite file) or mk_admin_secrets (Postgres), as ciphertext, IV and tag. Someone who copies the database without the key cannot read them.
02If the key is lost or changed
The server still starts, and these keep working: the owner and team accounts and passwords, open admin sessions, every ordinary setting, the audit log and history.
What stops working, and what the server log says:
| Affected | Log line or symptom | Fix |
|---|---|---|
| Anthropic key saved in the console | [admin] secret "integrations.anthropicApiKey" cannot be decrypted: was the secretKey changed? AI chart reading turns off; Status → Anthropic API key accepted fails. | Owner: Integrations → paste the key again → Save changes → Test connection. Or set ANTHROPIC_API_KEY on the server. |
| Webhook signing secret | [admin] secret "notify.webhookSecret" cannot be decrypted: … when an alert is sent. | Owner: Notifications → enter the secret again (and the same secret on the receiving side). |
| Two-factor sign-in | [admin] two-factor secret of <email> cannot be decrypted: was the secretKey changed? The authenticator code is refused. | Sign in with one of your recovery codes (they are hashed, not encrypted, so they still work). Then in Security & alerts turn two-factor off (password plus a recovery code) and set it up again. If two-factor is required for your role, the owner turns that requirement off first. A team member without recovery codes: the owner removes them under Team and adds them again. |
| Pro plan users | They appear signed out. | Nothing to do: they sign in again with their wallet. Their plan is read from your address's Hyperliquid ledger, so no payment is lost. |
There is no master key and no recovery service. If the old key is gone, the encrypted values are gone; you enter them again. Put the old value back (if you still have it) to read them.
The two-factor recovery path above is implemented in packages/admin-kit/server/kit.ts.
03Changing the key on purpose
- PrepareHave the Anthropic key and the webhook secret at hand (from your Anthropic account and the receiving system; the console cannot show them). Make sure everyone with two-factor has recovery codes, or turns two-factor off first.
- Make a new key
openssl rand -hex 32 - Replace itIn
.env(then restart the server) or in Vercel's environment variables (then redeploy). Store the new value in your password manager. - Enter the secrets againIntegrations (Anthropic key), Notifications (webhook secret); set up two-factor again where needed.
- CheckStatus → Re-run checks: Anthropic API key accepted is green again.
Change it at once if it may have leaked. Because someone with both the key and a copy of the database could decrypt the stored secrets, also create a new Anthropic key in your Anthropic account and a new webhook secret.
04Backups
| What | Where | How to back it up |
|---|---|---|
ADMIN_SECRET_KEY and the rest of .env | Your server or Vercel's environment settings | A password manager. Never git, never a support message. |
| Admin database (Node server, SQLite) | THESIS_DATA_DIR (default ./data): admin.sqlite and, while the server runs, admin.sqlite-wal and admin.sqlite-shm | The database runs in WAL mode, so copy the whole folder with the server stopped: |
| Aggregate counters | THESIS_DATA_DIR/stats.json, or Vercel Blob | Optional: counters only. Included when you copy the data folder. |
| Admin database (Postgres, required on Vercel) | Tables mk_admin_* in the database at DATABASE_URL | Your provider's own backups or restore points (see the provider's documentation), or a dump with the PostgreSQL client tools: |
| Settings only | The console | Owner: Export / Import → Export downloads thesis-admin-<date>.json with every ordinary setting. It holds wallet addresses in clear (keep it private) but no secrets, accounts, audit log or history. Import shows a preview first and never imports secrets. |
| Users' strategies, journals, alert settings | Each user's own browser | Not on your server, so you cannot back them up. Users can export strategies and the journal (CSV) from the desk. |
A backup of the database is only useful together with the same ADMIN_SECRET_KEY; without it you restore everything except the encrypted secrets. Test a restore once on a copy before you rely on it.