Skip to content

feat: sign og image urls by default#638

Merged
harlan-zw merged 1 commit into
mainfrom
feat/sign-urls-by-default
Jun 24, 2026
Merged

feat: sign og image urls by default#638
harlan-zw merged 1 commit into
mainfrom
feat/sign-urls-by-default

Conversation

@harlan-zw

Copy link
Copy Markdown
Collaborator

❓ Type of change

  • 📖 Documentation
  • 🐞 Bug fix
  • 👌 Enhancement
  • ✨ New feature
  • 🧹 Chore
  • ⚠️ Breaking change

📚 Description

Runtime OG image URLs were only signed when a security.secret was set; without one the /_og/d/** endpoint accepted arbitrary unsigned requests. This makes signing the default by auto-generating a per-build secret when none is configured.

How resolution works (resolveSigningSecret, pure + unit-tested):

  • security.secret: false → signing disabled (explicit opt-out).
  • explicit config/env value → used as-is.
  • otherwise → a random per-build secret is generated.

The auto-generated secret is random, server-only, and baked into the build. It is stable within a build artifact (so runtime sign and verify agree) but rotates per build, which is fine for prerendered/cached images and single-instance deploys; rolling or multi-instance deploys want a stable secret so URLs signed by one build verify on another. A dev warning surfaces this, gated on actually having a server runtime so pure SSG/static builds stay quiet.

Two details worth calling out:

  • Cloudflare/runtime override preserved. Only an explicit secret is baked into the ogImage.secret override channel; the auto value lives solely in the build-time security.secret fallback. This keeps the NUXT_OG_IMAGE_SECRET runtime override (e.g. Cloudflare env bindings) reachable.
  • Strict unchanged. strict still requires an explicit secret — the auto value's per-build rotation isn't a strong enough guarantee for strict mode.

⚠️ Breaking Changes

Runtime og:image URLs now include a signature by default, so:

  • Tests/snapshots that assert exact /_og/d/... URLs will see a ,s_… suffix.
  • Hand-constructed unsigned /_og/d/ requests against a production runtime are rejected with 403.

Prerendered (/_og/s/) URLs are unaffected (never signed), and dev mode skips verification.

📝 Migration

  • To keep unsigned URLs, set ogImage: { security: { secret: false } }.
  • For rolling/multi-instance deploys, set a stable NUXT_OG_IMAGE_SECRET (or security.secret). Generate one with npx nuxt-og-image generate-secret.

Fixtures that assert unsigned dynamic URLs (basic, cloudflare-satori, vercel-edge-satori) opt out via secret: false; signing stays covered by the url-signing unit tests and the cloudflare-runtime-config e2e.

Previously runtime OG image URLs were only signed when a `security.secret`
was configured; without one the `/_og/d/**` endpoint accepted arbitrary
unsigned requests. Now a per-build secret is auto-generated when none is set,
so URL signing is on by default with no configuration.

- Resolve the signing secret via a pure `resolveSigningSecret()`: explicit
  opt-out (`secret: false`) > explicit config/env value > auto-generated.
- The auto value is random, server-only, and baked into the build. It is
  stable within a build artifact (runtime sign + verify agree) but rotates per
  build, so an explicit secret is still recommended for rolling/multi-instance
  deploys — surfaced via a dev warning, gated on having a server runtime (no
  warning for pure SSG/static builds).
- Only an explicit secret is baked into the `ogImage.secret` override channel,
  keeping the `NUXT_OG_IMAGE_SECRET` runtime override (e.g. Cloudflare env)
  reachable. The auto value lives solely in the build-time `security.secret`.
- `strict` still requires an explicit secret (the auto value's per-build
  rotation isn't a strong enough guarantee).
- `security.secret: false` disables signing entirely.

Test fixtures that assert unsigned dynamic URLs (basic, cloudflare-satori,
vercel-edge-satori) opt out via `secret: false`; signing remains covered by the
url-signing unit tests and the cloudflare-runtime-config e2e.
@pkg-pr-new

pkg-pr-new Bot commented Jun 24, 2026

Copy link
Copy Markdown

Open in StackBlitz

npm i https://pkg.pr.new/nuxt-og-image@638

commit: 300b814

@harlan-zw harlan-zw merged commit e6c5b53 into main Jun 24, 2026
12 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant