docs: update setAll callbacks to accept cache headers second argument (#44240)

## What

Updates all `setAll` cookie handler implementations across docs and
examples to accept the new `headers` second argument introduced in
`@supabase/ssr` v0.10.0
([supabase/ssr#176](https://github.com/supabase/ssr/pull/176)).

## Why

`@supabase/ssr` v0.10.0 introduced a breaking change: `setAll` now
receives a required second argument `headers: Record<string, string>`
alongside the cookies array. When a token refresh occurs, the library
passes cache headers (`Cache-Control`, `Expires`, `Pragma`) that must be
applied to the HTTP response to prevent CDN caching of auth responses.

Because TypeScript allows functions with fewer parameters to satisfy a
type expecting more, existing `setAll` implementations do not produce a
type error when the second argument is omitted. Users who copy an
outdated snippet will silently miss the CDN protection.

Root cause and context:
[supabase/supabase-js#1682](https://github.com/supabase/supabase-js/issues/1682)

## Changes

**Proxy/middleware contexts** (where token refreshes happen) now apply
the cache headers to their response:
- Next.js proxy files: `supabaseResponse.headers.set(key, value)`
- SvelteKit hooks: `event.setHeaders(headers)`
- Hono middleware: `c.header(key, value)`
- Pages Router (Express-style): `ctx.res.setHeader(key, value)`
- Remix/React Router loaders and actions: applied to response headers
(outer `headers` variable renamed to `responseHeaders` to avoid naming
conflict with the new param)

**Server Component and API route contexts** (no response object
available) accept `_headers` without applying them.

## Files updated

- `apps/docs/content/guides/auth/server-side/creating-a-client.mdx`
(inline Astro, Remix, React Router, Express snippets)
- `apps/docs/content/_partials/oauth_pkce_flow.mdx`
- `apps/docs/content/guides/auth/oauth-server/getting-started.mdx`
- `apps/docs/content/guides/auth/passwords.mdx`
-
`apps/docs/content/troubleshooting/how-to-migrate-from-supabase-auth-helpers-to-ssr-package-5NRunM.mdx`
- `examples/auth/nextjs/`, `examples/auth/nextjs-full/` (proxy + server)
- `examples/auth/sveltekit/`, `examples/auth/sveltekit-full/`
- `examples/auth/hono/`, `examples/auth/hono-full/`
- `examples/user-management/nextjs-user-management/` (proxy + server)
- `examples/user-management/sveltekit-user-management/`
- `examples/realtime/nextjs-authorization-demo/` (proxy + server)
- `examples/realtime/nextjs-auth-presence/` (pages router)
- `examples/prompts/nextjs-supabase-auth.md`
This commit is contained in:
Katerina Skroumpelou authored and GitHub committed 2026-03-30 16:08:29 +03:00
1 parent edacf2413d
commit 41f9ddd70c
22 files changed
+105 -57

No files matched your search

@@ -39,8 +39,9 @@ export const supabaseMiddleware = (): MiddlewareHandler => {
getAll() {
return parseCookieHeader(c.req.header('Cookie') ?? '')
},
setAll(cookiesToSet) {
setAll(cookiesToSet, cacheHeaders) {
cookiesToSet.forEach(({ name, value, options }) => setCookie(c, name, value, options))
Object.entries(cacheHeaders).forEach(([key, value]) => c.header(key, value))
},
},
})
@@ -38,8 +38,9 @@ export const supabaseMiddleware = (): MiddlewareHandler => {
getAll() {
return parseCookieHeader(c.req.header('Cookie') ?? '')
},
setAll(cookiesToSet) {
setAll(cookiesToSet, cacheHeaders) {
cookiesToSet.forEach(({ name, value, options }) => setCookie(c, name, value, options))
Object.entries(cacheHeaders).forEach(([key, value]) => c.header(key, value))
},
},
})
@@ -16,7 +16,7 @@ export async function updateSession(request: NextRequest) {
getAll() {
return request.cookies.getAll()
},
setAll(cookiesToSet) {
setAll(cookiesToSet, headers) {
cookiesToSet.forEach(({ name, value }) => request.cookies.set(name, value))
supabaseResponse = NextResponse.next({
request,
@@ -24,6 +24,9 @@ export async function updateSession(request: NextRequest) {
cookiesToSet.forEach(({ name, value, options }) =>
supabaseResponse.cookies.set(name, value, options)
)
Object.entries(headers).forEach(([key, value]) =>
supabaseResponse.headers.set(key, value)
)
},
},
}
@@ -12,7 +12,7 @@ export async function createClient() {
getAll() {
return cookieStore.getAll()
},
setAll(cookiesToSet) {
setAll(cookiesToSet, _headers) {
try {
cookiesToSet.forEach(({ name, value, options }) =>
cookieStore.set(name, value, options)
+4 -1
View File
@@ -16,7 +16,7 @@ export async function updateSession(request: NextRequest) {
getAll() {
return request.cookies.getAll()
},
setAll(cookiesToSet) {
setAll(cookiesToSet, headers) {
cookiesToSet.forEach(({ name, value }) => request.cookies.set(name, value))
supabaseResponse = NextResponse.next({
request,
@@ -24,6 +24,9 @@ export async function updateSession(request: NextRequest) {
cookiesToSet.forEach(({ name, value, options }) =>
supabaseResponse.cookies.set(name, value, options)
)
Object.entries(headers).forEach(([key, value]) =>
supabaseResponse.headers.set(key, value)
)
},
},
}
+1 -1
View File
@@ -12,7 +12,7 @@ export async function createClient() {
getAll() {
return cookieStore.getAll()
},
setAll(cookiesToSet) {
setAll(cookiesToSet, _headers) {
try {
cookiesToSet.forEach(({ name, value, options }) =>
cookieStore.set(name, value, options)
@@ -18,10 +18,13 @@ const supabase: Handle = async ({ event, resolve }) => {
* the cookie options. Setting `path` to `/` replicates previous/
* standard behavior.
*/
setAll: (cookiesToSet) => {
setAll: (cookiesToSet, headers) => {
cookiesToSet.forEach(({ name, value, options }) => {
event.cookies.set(name, value, { ...options, path: '/' })
})
if (Object.keys(headers).length > 0) {
event.setHeaders(headers)
}
},
},
})
+4 -1
View File
@@ -8,7 +8,7 @@ export const handle: Handle = async ({ event, resolve }) => {
getAll() {
return event.cookies.getAll()
},
setAll(cookiesToSet) {
setAll(cookiesToSet, headers) {
/**
* Note: You have to add the `path` variable to the
* set and remove method due to sveltekit's cookie API
@@ -18,6 +18,9 @@ export const handle: Handle = async ({ event, resolve }) => {
cookiesToSet.forEach(({ name, value, options }) =>
event.cookies.set(name, value, { ...options, path: '/' })
)
if (Object.keys(headers).length > 0) {
event.setHeaders(headers)
}
},
},
})
+10 -4
View File
@@ -47,7 +47,7 @@ Instead, you MUST ALWAYS generate ONLY this pattern:
getAll() {
return cookieStore.getAll()
},
setAll(cookiesToSet) {
setAll(cookiesToSet, headers) {
const response = NextResponse.next({
request,
})
@@ -55,6 +55,9 @@ Instead, you MUST ALWAYS generate ONLY this pattern:
cookiesToSet.forEach(({ name, value, options }) => {
response.cookies.set(name, value, options)
})
Object.entries(headers).forEach(([key, value]) =>
response.headers.set(key, value)
)
return response
}
@@ -99,7 +102,7 @@ export async function createClient() {
getAll() {
return cookieStore.getAll()
},
setAll(cookiesToSet) {
setAll(cookiesToSet, _headers) {
try {
cookiesToSet.forEach(({ name, value, options }) =>
cookieStore.set(name, value, options)
@@ -135,14 +138,17 @@ export async function proxy(request: NextRequest) {
getAll() {
return request.cookies.getAll()
},
setAll(cookiesToSet) {
cookiesToSet.forEach(({ name, value, options }) => request.cookies.set(name, value))
setAll(cookiesToSet, headers) {
cookiesToSet.forEach(({ name, value }) => request.cookies.set(name, value))
supabaseResponse = NextResponse.next({
request,
})
cookiesToSet.forEach(({ name, value, options }) =>
supabaseResponse.cookies.set(name, value, options)
)
Object.entries(headers).forEach(([key, value]) =>
supabaseResponse.headers.set(key, value)
)
},
},
}
@@ -66,12 +66,13 @@ export const getServerSideProps = async (ctx: GetServerSidePropsContext) => {
value: value ?? '',
}))
},
setAll(cookiesToSet) {
setAll(cookiesToSet, headers) {
const existing = ctx.res.getHeader('Set-Cookie') ?? []
ctx.res.setHeader('Set-Cookie', [
...(Array.isArray(existing) ? existing : [String(existing)]),
...cookiesToSet.map(({ name, value, options }) => serialize(name, value, options)),
])
Object.entries(headers).forEach(([key, value]) => ctx.res.setHeader(key, value))
},
},
}
@@ -28,12 +28,13 @@ export const getServerSideProps = async (ctx: GetServerSidePropsContext) => {
value: value ?? '',
}))
},
setAll(cookiesToSet) {
setAll(cookiesToSet, headers) {
const existing = ctx.res.getHeader('Set-Cookie') ?? []
ctx.res.setHeader('Set-Cookie', [
...(Array.isArray(existing) ? existing : [String(existing)]),
...cookiesToSet.map(({ name, value, options }) => serialize(name, value, options)),
])
Object.entries(headers).forEach(([key, value]) => ctx.res.setHeader(key, value))
},
},
}
@@ -15,12 +15,15 @@ export const updateSession = async (request: NextRequest) => {
getAll() {
return request.cookies.getAll()
},
setAll(cookiesToSet) {
setAll(cookiesToSet, headers) {
cookiesToSet.forEach(({ name, value }) => request.cookies.set(name, value))
supabaseResponse = NextResponse.next({ request })
cookiesToSet.forEach(({ name, value, options }) =>
supabaseResponse.cookies.set(name, value, options)
)
Object.entries(headers).forEach(([key, value]) =>
supabaseResponse.headers.set(key, value)
)
},
},
}
@@ -12,7 +12,7 @@ export const createClient = async () => {
getAll() {
return cookieStore.getAll()
},
setAll(cookiesToSet) {
setAll(cookiesToSet, _headers) {
try {
cookiesToSet.forEach(({ name, value, options }) =>
cookieStore.set(name, value, options)
@@ -14,14 +14,17 @@ export async function updateSession(request: NextRequest) {
getAll() {
return request.cookies.getAll()
},
setAll(cookiesToSet) {
cookiesToSet.forEach(({ name, value, options }) => request.cookies.set(name, value))
setAll(cookiesToSet, headers) {
cookiesToSet.forEach(({ name, value }) => request.cookies.set(name, value))
supabaseResponse = NextResponse.next({
request,
})
cookiesToSet.forEach(({ name, value, options }) =>
supabaseResponse.cookies.set(name, value, options)
)
Object.entries(headers).forEach(([key, value]) =>
supabaseResponse.headers.set(key, value)
)
},
},
}
@@ -14,7 +14,7 @@ export async function createClient() {
getAll() {
return cookieStore.getAll()
},
setAll(cookiesToSet) {
setAll(cookiesToSet, _headers) {
try {
cookiesToSet.forEach(({ name, value, options }) =>
cookieStore.set(name, value, options)
@@ -13,10 +13,13 @@ export const handle: Handle = async ({ event, resolve }) => {
* requiring this to be set, setting the path to `/`
* will replicate previous/standard behaviour (https://kit.svelte.dev/docs/types#public-types-cookies)
*/
setAll: (cookiesToSet) => {
setAll: (cookiesToSet, headers) => {
cookiesToSet.forEach(({ name, value, options }) => {
event.cookies.set(name, value, { ...options, path: '/' })
})
if (Object.keys(headers).length > 0) {
event.setHeaders(headers)
}
},
},
})