mirror of
https://github.com/supabase/supabase.git
synced 2026-10-14 21:59:16 +03:00
* docs: indicate publishable key instead of anon in many examples * replace your-anon-key to string indicating publishable or anon * fix your_... * apply suggestion from @ChrisChinchilla Co-authored-by: Chris Chinchilla <chris@chrischinchilla.com> * Update keys in code examples * Prettier fix * Update apps/docs/content/guides/functions/schedule-functions.mdx --------- Co-authored-by: Chris Chinchilla <chris@chrischinchilla.com>
231 lines
6.9 KiB
Markdown
231 lines
6.9 KiB
Markdown
---
|
|
# Specify the following for Cursor rules
|
|
description: Guidelines for writing Next.js apps with Supabase Auth
|
|
alwaysApply: false
|
|
---
|
|
|
|
# Bootstrap Next.js 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 middleware 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) {
|
|
const response = NextResponse.next({
|
|
request,
|
|
})
|
|
|
|
cookiesToSet.forEach(({ name, value, options }) => {
|
|
response.cookies.set(name, value, options)
|
|
})
|
|
|
|
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) {
|
|
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 middleware refreshing
|
|
// user sessions.
|
|
}
|
|
},
|
|
},
|
|
}
|
|
)
|
|
}
|
|
```
|
|
|
|
## CORRECT MIDDLEWARE IMPLEMENTATION
|
|
|
|
```typescript
|
|
import { createServerClient } from '@supabase/ssr'
|
|
import { NextResponse, type NextRequest } from 'next/server'
|
|
|
|
export async function middleware(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) {
|
|
cookiesToSet.forEach(({ name, value, options }) => request.cookies.set(name, value))
|
|
supabaseResponse = NextResponse.next({
|
|
request,
|
|
})
|
|
cookiesToSet.forEach(({ name, value, options }) =>
|
|
supabaseResponse.cookies.set(name, value, options)
|
|
)
|
|
},
|
|
},
|
|
}
|
|
)
|
|
|
|
// 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. |