Secrets
Every secret HowlCast reads, where to set it, and what happens if you don't.
HowlCast reads ~15 distinct secrets across local dev and prod. Most fail soft (feature disabled with a clear error) but a few will refuse to boot.
Inventory
| Secret | Where it goes | Required? | What breaks without it |
|---|---|---|---|
BETTER_AUTH_SECRET | both Workers | yes | Auth refuses to start |
BETTER_AUTH_URL | both Workers | yes | Magic-link callbacks point at wrong host |
CORS_ORIGIN | both Workers | yes | API rejects browser requests |
STREAM_API_KEY | api Worker | for live | stream.* procedures throw PRECONDITION_FAILED |
STREAM_API_SECRET | api Worker | for live | Same as above + webhooks fail HMAC |
TWITCH_CLIENT_ID | api Worker | for setup | Setup wizard + emote pipeline disabled |
TWITCH_CLIENT_SECRET | api Worker | for setup | Same as above |
RESEND_API_KEY | api Worker | for prod | Magic-link emails fall through to console (no send) |
MAIL_FROM | api Worker | for prod | Resend rejects the request |
SMTP_URL | api Worker (dev only) | no | mailpit fallback in local dev |
CLOUDFLARE_API_TOKEN | local + GH Actions | yes | Alchemy can't deploy |
CLOUDFLARE_ACCOUNT_ID | local + GH Actions | yes | Alchemy can't find the account |
ALCHEMY_PASSWORD | local + GH Actions | yes | Alchemy state encryption |
ALCHEMY_STATE_TOKEN | GH Actions only | CI only | CI deploy can't read its state Worker |
Local dev
Copy the example file:
cp apps/server/.env.example apps/server/.envEdit and fill in. The web app reads NEXT_PUBLIC_* vars at build time; the api reads via packages/env/src/server.ts.
Production (via Alchemy)
alchemy.run.ts wraps every secret in alchemy.secret(process.env.X ?? ""). On bun run deploy, alchemy uploads each secret to the Worker via the Cloudflare API. They're encrypted at rest in the Worker config.
Empty string is treated as "not configured" — the runtime then throws a clear error if you try to use that feature.
CI/CD (GitHub Actions)
.github/workflows/deploy.yml runs bun run deploy against your account. It needs all 14 secrets above pushed into the repo's GH Actions secrets:
gh secret set CLOUDFLARE_API_TOKEN
gh secret set CLOUDFLARE_ACCOUNT_ID
# … repeat for eachUse a scoped Cloudflare API token — not the root one. Required permissions: Workers Scripts:Edit, D1:Edit, R2:Edit, KV:Edit, Workers Routes:Edit, Account Settings:Read.
Rotation
STREAM_API_SECRET— rotate in GetStream dashboard, push new value, redeploy. Webhooks downtime ≈ 1 min.BETTER_AUTH_SECRET— rotating invalidates all sessions. Plan downtime.RESEND_API_KEY— rotate in Resend dashboard, push new value, redeploy. Magic-link emails skip until the new value is live.
Next: First deploy.