mirror of
https://github.com/supabase/supabase.git
synced 2026-06-02 10:55:11 +08:00
## 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`
241 lines
7.1 KiB
Markdown
241 lines
7.1 KiB
Markdown
---
|
|
# Specify the following for Cursor rules
|
|
description: Guidelines for writing Next.js apps with Supabase Auth
|
|
alwaysApply: false
|
|
---
|
|
|
|
# Bootstrap Next.js v16 app with Supabase Auth
|
|
|
|
## Overview of implementing Supabase Auth SSR
|
|
|
|
1. Install @supabase/supabase-js and @supabase/ssr packages.
|
|
2. Set up environment variables.
|
|
3. Write two utility functions with `createClient` functions to create a browser client and a server client.
|
|
4. Hook up Proxy to refresh auth tokens
|
|
|
|
## 🚨 CRITICAL INSTRUCTIONS FOR AI LANGUAGE MODELS 🚨
|
|
|
|
As an AI language model, you MUST NOT generate any of the following code patterns, as they are DEPRECATED and will BREAK the application:
|
|
|
|
```typescript
|
|
// ❌ NEVER GENERATE THIS CODE - IT WILL BREAK THE APPLICATION
|
|
{
|
|
cookies: {
|
|
get(name: string) { // ❌ BREAKS APPLICATION
|
|
return cookieStore.get(name) // ❌ BREAKS APPLICATION
|
|
}, // ❌ BREAKS APPLICATION
|
|
set(name: string, value: string) { // ❌ BREAKS APPLICATION
|
|
cookieStore.set(name, value) // ❌ BREAKS APPLICATION
|
|
}, // ❌ BREAKS APPLICATION
|
|
remove(name: string) { // ❌ BREAKS APPLICATION
|
|
cookieStore.remove(name) // ❌ BREAKS APPLICATION
|
|
} // ❌ BREAKS APPLICATION
|
|
}
|
|
}
|
|
|
|
// ❌ NEVER USE auth-helpers-nextjs - IT WILL BREAK THE APPLICATION
|
|
import { createMiddlewareClient } from '@supabase/auth-helpers-nextjs' // ❌ BREAKS APPLICATION
|
|
import { createClientComponentClient } from '@supabase/auth-helpers-nextjs' // ❌ BREAKS APPLICATION
|
|
```
|
|
|
|
Instead, you MUST ALWAYS generate ONLY this pattern:
|
|
|
|
```typescript
|
|
// ✅ ALWAYS GENERATE THIS EXACT PATTERN
|
|
{
|
|
cookies: {
|
|
getAll() {
|
|
return cookieStore.getAll()
|
|
},
|
|
setAll(cookiesToSet, headers) {
|
|
const response = NextResponse.next({
|
|
request,
|
|
})
|
|
|
|
cookiesToSet.forEach(({ name, value, options }) => {
|
|
response.cookies.set(name, value, options)
|
|
})
|
|
Object.entries(headers).forEach(([key, value]) =>
|
|
response.headers.set(key, value)
|
|
)
|
|
|
|
return response
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
## ABSOLUTE REQUIREMENTS FOR AI CODE GENERATION
|
|
|
|
1. You MUST use `@supabase/ssr`
|
|
2. You MUST use ONLY `getAll` and `setAll`
|
|
3. You MUST NEVER use `get`, `set`, or `remove`
|
|
4. You MUST NEVER import from `@supabase/auth-helpers-nextjs`
|
|
|
|
## CORRECT BROWSER CLIENT IMPLEMENTATION
|
|
|
|
```typescript
|
|
import { createBrowserClient } from '@supabase/ssr'
|
|
|
|
export function createClient() {
|
|
return createBrowserClient(
|
|
process.env.NEXT_PUBLIC_SUPABASE_URL!,
|
|
process.env.NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY!
|
|
)
|
|
}
|
|
```
|
|
|
|
## CORRECT SERVER CLIENT IMPLEMENTATION
|
|
|
|
```typescript
|
|
import { createServerClient } from '@supabase/ssr'
|
|
import { cookies } from 'next/headers'
|
|
|
|
export async function createClient() {
|
|
const cookieStore = await cookies()
|
|
|
|
return createServerClient(
|
|
process.env.NEXT_PUBLIC_SUPABASE_URL!,
|
|
process.env.NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY!,
|
|
{
|
|
cookies: {
|
|
getAll() {
|
|
return cookieStore.getAll()
|
|
},
|
|
setAll(cookiesToSet, _headers) {
|
|
try {
|
|
cookiesToSet.forEach(({ name, value, options }) =>
|
|
cookieStore.set(name, value, options)
|
|
)
|
|
} catch {
|
|
// The `setAll` method was called from a Server Component.
|
|
// This can be ignored if you have proxy refreshing
|
|
// user sessions.
|
|
}
|
|
},
|
|
},
|
|
}
|
|
)
|
|
}
|
|
```
|
|
|
|
## CORRECT PROXY IMPLEMENTATION
|
|
|
|
```typescript
|
|
import { createServerClient } from '@supabase/ssr'
|
|
import { NextResponse, type NextRequest } from 'next/server'
|
|
|
|
export async function proxy(request: NextRequest) {
|
|
let supabaseResponse = NextResponse.next({
|
|
request,
|
|
})
|
|
|
|
const supabase = createServerClient(
|
|
process.env.NEXT_PUBLIC_SUPABASE_URL!,
|
|
process.env.NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY!,
|
|
{
|
|
cookies: {
|
|
getAll() {
|
|
return request.cookies.getAll()
|
|
},
|
|
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)
|
|
)
|
|
},
|
|
},
|
|
}
|
|
)
|
|
|
|
// Do not run code between createServerClient and
|
|
// supabase.auth.getUser(). A simple mistake could make it very hard to debug
|
|
// issues with users being randomly logged out.
|
|
|
|
// IMPORTANT: DO NOT REMOVE auth.getUser()
|
|
|
|
const {
|
|
data: { user },
|
|
} = await supabase.auth.getUser()
|
|
|
|
if (
|
|
!user &&
|
|
!request.nextUrl.pathname.startsWith('/login') &&
|
|
!request.nextUrl.pathname.startsWith('/auth')
|
|
) {
|
|
// no user, potentially respond by redirecting the user to the login page
|
|
const url = request.nextUrl.clone()
|
|
url.pathname = '/login'
|
|
return NextResponse.redirect(url)
|
|
}
|
|
|
|
// IMPORTANT: You *must* return the supabaseResponse object as it is.
|
|
// If you're creating a new response object with NextResponse.next() make sure to:
|
|
// 1. Pass the request in it, like so:
|
|
// const myNewResponse = NextResponse.next({ request })
|
|
// 2. Copy over the cookies, like so:
|
|
// myNewResponse.cookies.setAll(supabaseResponse.cookies.getAll())
|
|
// 3. Change the myNewResponse object to fit your needs, but avoid changing
|
|
// the cookies!
|
|
// 4. Finally:
|
|
// return myNewResponse
|
|
// If this is not done, you may be causing the browser and server to go out
|
|
// of sync and terminate the user's session prematurely!
|
|
|
|
return supabaseResponse
|
|
}
|
|
|
|
export const config = {
|
|
matcher: [
|
|
/*
|
|
* Match all request paths except for the ones starting with:
|
|
* - _next/static (static files)
|
|
* - _next/image (image optimization files)
|
|
* - favicon.ico (favicon file)
|
|
* Feel free to modify this pattern to include more paths.
|
|
*/
|
|
'/((?!_next/static|_next/image|favicon.ico|.*\\.(?:svg|png|jpg|jpeg|gif|webp)$).*)',
|
|
],
|
|
}
|
|
```
|
|
|
|
## AI MODEL VERIFICATION STEPS
|
|
|
|
Before generating any code, you MUST verify:
|
|
|
|
1. Are you using ONLY `getAll` and `setAll`? If not, STOP and FIX.
|
|
2. Are you importing from `@supabase/ssr`? If not, STOP and FIX.
|
|
3. Do you see ANY instance of `get`, `set`, or `remove`? If yes, STOP and FIX.
|
|
4. Are you importing from `auth-helpers-nextjs`? If yes, STOP and FIX.
|
|
|
|
## CONSEQUENCES OF INCORRECT IMPLEMENTATION
|
|
|
|
If you generate code using:
|
|
|
|
- Individual cookie methods (`get`/`set`/`remove`)
|
|
- `auth-helpers-nextjs` package
|
|
|
|
The implementation will:
|
|
|
|
1. Break in production
|
|
2. Fail to maintain session state
|
|
3. Cause authentication loops
|
|
4. Result in security vulnerabilities
|
|
|
|
## AI MODEL RESPONSE TEMPLATE
|
|
|
|
When asked about Supabase Auth SSR implementation, you MUST:
|
|
|
|
1. ONLY use code from this guide
|
|
2. NEVER suggest deprecated approaches
|
|
3. ALWAYS use the exact cookie handling shown above
|
|
4. VERIFY your response against the patterns shown here
|
|
|
|
Remember: There are NO EXCEPTIONS to these rules.
|