You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: docs/content/docs/1.guides/2.first-party.md
+115Lines changed: 115 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -200,6 +200,121 @@ The same pattern applies to [Netlify](https://netlify.com) (`[[redirects]]` with
200
200
Platform-level rewrites bypass the privacy anonymisation layer. The proxy handler only runs in a Nitro server runtime.
201
201
::
202
202
203
+
## Proxy Endpoint Security
204
+
205
+
Several proxy endpoints (Google Static Maps, Geocode, Gravatar, embed image proxies) inject server-side API keys or forward requests to third-party services. Without protection, anyone who discovers these endpoints could call them directly and consume your API quota.
206
+
207
+
### HMAC URL Signing
208
+
209
+
The module provides optional HMAC signing to lock down proxy endpoints. When enabled, only URLs generated server-side (during SSR or prerender) or accompanied by a valid page token are accepted. Unsigned requests receive a `403`.
210
+
211
+
#### Setup
212
+
213
+
Generate a signing secret:
214
+
215
+
```bash
216
+
npx @nuxt/scripts generate-secret
217
+
```
218
+
219
+
Then set it as an environment variable:
220
+
221
+
```bash
222
+
NUXT_SCRIPTS_PROXY_SECRET=<your-secret>
223
+
```
224
+
225
+
Or configure it directly:
226
+
227
+
```ts [nuxt.config.ts]
228
+
exportdefaultdefineNuxtConfig({
229
+
scripts: {
230
+
security: {
231
+
secret: process.env.NUXT_SCRIPTS_PROXY_SECRET,
232
+
}
233
+
}
234
+
})
235
+
```
236
+
237
+
#### How It Works
238
+
239
+
The module uses two verification modes:
240
+
241
+
1.**URL signatures** for server-rendered content. During SSR/prerender, proxy URLs include a `sig` parameter: an HMAC of the path and query params. The proxy endpoint verifies the signature before forwarding.
242
+
243
+
2.**Page tokens** for client-side reactive updates. Some components recompute their proxy URL after mount (e.g. measuring element dimensions). The server embeds a short-lived token (`_pt` + `_ts` params) in the SSR payload. The token is valid for any params on any proxy path and expires after 1 hour.
244
+
245
+
#### Development
246
+
247
+
In development, the module auto-generates a secret and writes it to your `.env` file on first run. You don't need to configure anything for local dev.
248
+
249
+
#### Production
250
+
251
+
Set `NUXT_SCRIPTS_PROXY_SECRET` in your deployment environment. The secret must be the same across all replicas and across build/runtime so that URLs signed at prerender time remain valid.
252
+
253
+
::callout{type="warning"}
254
+
Without a secret, proxy endpoints remain functional but unprotected. The module logs a warning at startup when it detects signed endpoints without a secret.
255
+
::
256
+
257
+
#### Signed Endpoints
258
+
259
+
The following proxy endpoints require signing when you configure a secret:
Analytics proxy endpoints (Google Analytics, Plausible, etc.) do not use signing because they only forward collection payloads and never expose API keys.
270
+
271
+
#### Configuration Reference
272
+
273
+
```ts [nuxt.config.ts]
274
+
exportdefaultdefineNuxtConfig({
275
+
scripts: {
276
+
security: {
277
+
// HMAC secret for signing proxy URLs.
278
+
// Falls back to process.env.NUXT_SCRIPTS_PROXY_SECRET.
279
+
secret: undefined,
280
+
// Auto-generate and persist a secret to .env in dev mode.
281
+
// Set to false to disable.
282
+
autoGenerateSecret: true,
283
+
}
284
+
}
285
+
})
286
+
```
287
+
288
+
#### Troubleshooting
289
+
290
+
**Signed URLs return 403 after deploy**
291
+
292
+
The secret must be identical at build time (when URLs are signed during prerender) and at runtime (when the server verifies them). If you prerender pages, ensure `NUXT_SCRIPTS_PROXY_SECRET` is available in both your build environment and your deployment environment.
293
+
294
+
**403 errors across multiple replicas**
295
+
296
+
All server instances must share the same secret. If each replica generates its own secret, a URL signed by one instance will fail verification on another. Set `NUXT_SCRIPTS_PROXY_SECRET` as a shared environment variable across all replicas.
297
+
298
+
**Unexpected `NUXT_SCRIPTS_PROXY_SECRET` in `.env`**
299
+
300
+
The module only writes this when running `nuxt dev` with a signed endpoint enabled and no secret configured. If you only use client-side scripts (analytics, tracking), the module does not generate a secret. To prevent auto-generation entirely, set `autoGenerateSecret: false`.
301
+
302
+
**Page tokens expire**
303
+
304
+
Page tokens are valid for 1 hour. If a user leaves a tab open longer than that, client-side proxy requests will start returning 403. The page will recover on next navigation or refresh.
305
+
306
+
#### Static Generation and SPA Mode
307
+
308
+
URL signing requires a server runtime to verify HMAC signatures. Two deployment modes cannot support signing:
309
+
310
+
**`nuxt generate` (SSG) with static hosting**: Prerendered pages contain proxy URLs, but no Nitro server exists at runtime to verify signatures or forward requests. Proxy endpoints will not work on static hosts (GitHub Pages, Cloudflare Pages static, etc.). If you need proxy endpoints with prerendering, deploy to a server target that supports both prerendering and runtime request handling (e.g. Node, Cloudflare Workers, [Vercel](https://vercel.com)).
311
+
312
+
**`ssr: false` (SPA mode)**: No server-side rendering means no opportunity to sign URLs or embed page tokens. The signing secret lives in server-only runtime config and cannot be accessed from the client. Proxy endpoints still function if deployed with a server, but requests will be unsigned.
313
+
314
+
::callout{type="info"}
315
+
In both cases, the module automatically detects the limitation and skips signing setup. Proxy endpoints remain functional but unprotected. The module logs a warning at build time.
Copy file name to clipboardExpand all lines: docs/content/scripts/bluesky-embed.md
+4Lines changed: 4 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -18,6 +18,10 @@ Nuxt Scripts provides a [`<ScriptBlueskyEmbed>`{lang="html"}](/scripts/bluesky-e
18
18
::script-docs{embed}
19
19
::
20
20
21
+
::callout{type="info"}
22
+
This script's proxy endpoints use [HMAC URL signing](/docs/guides/first-party#proxy-endpoint-security) when you configure a `NUXT_SCRIPTS_PROXY_SECRET`. See the [security guide](/docs/guides/first-party#proxy-endpoint-security) for setup instructions.
23
+
::
24
+
21
25
This registers the required server API routes (`/_scripts/embed/bluesky` and `/_scripts/embed/bluesky-image`) that handle fetching post data and proxying images.
Renders a [Google Maps Static API](https://developers.google.com/maps/documentation/maps-static) image. Use standalone for static map previews, or drop into the `#placeholder` slot of [`<ScriptGoogleMaps>`{lang="html"}](/scripts/google-maps/api/script-google-maps) for a loading placeholder.
6
6
7
+
::callout{type="info"}
8
+
This script's proxy endpoints use [HMAC URL signing](/docs/guides/first-party#proxy-endpoint-security) when you configure a `NUXT_SCRIPTS_PROXY_SECRET`. See the [security guide](/docs/guides/first-party#proxy-endpoint-security) for setup instructions.
Copy file name to clipboardExpand all lines: docs/content/scripts/google-maps/index.md
+4Lines changed: 4 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -63,6 +63,10 @@ You must add this. It registers server proxy routes that keep your API key serve
63
63
You can pass `api-key` directly on the `<ScriptGoogleMaps>`{lang="html"} component, but this approach is not recommended, as it exposes your key in client-side requests.
64
64
::
65
65
66
+
::callout{type="info"}
67
+
This script's proxy endpoints use [HMAC URL signing](/docs/guides/first-party#proxy-endpoint-security) when you configure a `NUXT_SCRIPTS_PROXY_SECRET`. See the [security guide](/docs/guides/first-party#proxy-endpoint-security) for setup instructions.
68
+
::
69
+
66
70
See [Billing & Permissions](/scripts/google-maps/guides/billing) for API costs and required permissions.
Copy file name to clipboardExpand all lines: docs/content/scripts/gravatar.md
+4Lines changed: 4 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -20,6 +20,10 @@ links:
20
20
::script-docs
21
21
::
22
22
23
+
::callout{type="info"}
24
+
This script's proxy endpoints use [HMAC URL signing](/docs/guides/first-party#proxy-endpoint-security) when you configure a `NUXT_SCRIPTS_PROXY_SECRET`. See the [security guide](/docs/guides/first-party#proxy-endpoint-security) for setup instructions.
The [`<ScriptGravatar>`{lang="html"}](/scripts/gravatar){lang="html"} component renders a Gravatar avatar for a given email address. All requests are proxied through your server - Gravatar never sees your user's IP address or headers.
Copy file name to clipboardExpand all lines: docs/content/scripts/instagram-embed.md
+4Lines changed: 4 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -18,6 +18,10 @@ Nuxt Scripts provides a [`<ScriptInstagramEmbed>`{lang="html"}](/scripts/instagr
18
18
::script-docs{embed}
19
19
::
20
20
21
+
::callout{type="info"}
22
+
This script's proxy endpoints use [HMAC URL signing](/docs/guides/first-party#proxy-endpoint-security) when you configure a `NUXT_SCRIPTS_PROXY_SECRET`. See the [security guide](/docs/guides/first-party#proxy-endpoint-security) for setup instructions.
23
+
::
24
+
21
25
This registers the required server API routes (`/_scripts/embed/instagram`, `/_scripts/embed/instagram-image`, and `/_scripts/embed/instagram-asset`) that handle fetching embed HTML and proxying images/assets.
Copy file name to clipboardExpand all lines: docs/content/scripts/x-embed.md
+4Lines changed: 4 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -18,6 +18,10 @@ Nuxt Scripts provides a [`<ScriptXEmbed>`{lang="html"}](/scripts/x-embed){lang="
18
18
::script-docs{embed}
19
19
::
20
20
21
+
::callout{type="info"}
22
+
This script's proxy endpoints use [HMAC URL signing](/docs/guides/first-party#proxy-endpoint-security) when you configure a `NUXT_SCRIPTS_PROXY_SECRET`. See the [security guide](/docs/guides/first-party#proxy-endpoint-security) for setup instructions.
23
+
::
24
+
21
25
This registers the required server API routes (`/_scripts/embed/x` and `/_scripts/embed/x-image`) that handle fetching tweet data and proxying images.
0 commit comments