Problem
The OG image HMAC token has the secret in two places that must be kept in sync manually:
- Build / signing —
src/lib/createOgImageLink.tsx reads OG_IMAGE_SECRET from astro:env/server, i.e. process.env at build time. In CI that's the GitHub Actions repo secret (passed via the workflow env:).
- Runtime / verifying —
api/og.ts reads process.env.OG_IMAGE_SECRET, injected by Vercel from the project's env vars.
If the GitHub secret and the Vercel project env var differ (or the Vercel one was never set), every OG image returns 401 invalid-token. A missing Vercel var gives 500 ("missing"); a mismatched one gives 401. This is easy to get wrong on first setup ("set it in GitHub, forget to set it on Vercel") and on rotation (change one, forget the other). It bit a downstream fork.
Proposal
Make Vercel the single source of truth so build and runtime can't diverge:
- Set
OG_IMAGE_SECRET once, on the Vercel project (Production/Preview), non-sensitive so the build can read it.
- Drop the
OG_IMAGE_SECRET env: override on the deploy steps in ci.yml, so vercel build provides the value to the astro build from the pulled project env (vercel pull already runs first in deploy.mjs).
- Remove
OG_IMAGE_SECRET from the required GitHub Actions secrets (keep placeholder for the non-deployed test build + astro sync).
Net: one value, set in one place, used for both signing and verifying.
Open question / risk
Need to verify that vercel build actually exposes the pulled .vercel/.env.<target>.local value to the astro build subprocess so astro:env/server (a required secret field) resolves it. If it doesn't, removing the GH override would fail the build (required env missing). Test on a preview deploy before adopting.
Alternative (smaller)
Keep the two-source setup but document it loudly (README already lists only the GH secret — add the Vercel-side requirement) and/or add a CI check that fails if the two don't match. Less robust than single-source.
Problem
The OG image HMAC token has the secret in two places that must be kept in sync manually:
src/lib/createOgImageLink.tsxreadsOG_IMAGE_SECRETfromastro:env/server, i.e.process.envat build time. In CI that's the GitHub Actions repo secret (passed via the workflowenv:).api/og.tsreadsprocess.env.OG_IMAGE_SECRET, injected by Vercel from the project's env vars.If the GitHub secret and the Vercel project env var differ (or the Vercel one was never set), every OG image returns
401 invalid-token. A missing Vercel var gives500("missing"); a mismatched one gives401. This is easy to get wrong on first setup ("set it in GitHub, forget to set it on Vercel") and on rotation (change one, forget the other). It bit a downstream fork.Proposal
Make Vercel the single source of truth so build and runtime can't diverge:
OG_IMAGE_SECRETonce, on the Vercel project (Production/Preview), non-sensitive so the build can read it.OG_IMAGE_SECRETenv:override on the deploy steps inci.yml, sovercel buildprovides the value to the astro build from the pulled project env (vercel pullalready runs first indeploy.mjs).OG_IMAGE_SECRETfrom the required GitHub Actions secrets (keepplaceholderfor the non-deployed test build +astro sync).Net: one value, set in one place, used for both signing and verifying.
Open question / risk
Need to verify that
vercel buildactually exposes the pulled.vercel/.env.<target>.localvalue to theastro buildsubprocess soastro:env/server(a required secret field) resolves it. If it doesn't, removing the GH override would fail the build (required env missing). Test on a preview deploy before adopting.Alternative (smaller)
Keep the two-source setup but document it loudly (README already lists only the GH secret — add the Vercel-side requirement) and/or add a CI check that fails if the two don't match. Less robust than single-source.