-
-
Notifications
You must be signed in to change notification settings - Fork 10.7k
Description
Hi all,
I am building a multi-tenant platform with NextJS using Supabase.
The application for my customers is under app.localhost.com,
and each customer can create their blog. For example, blog.localhost.com, blog2.localhost.com
Naturally, I will set the domain for cookies under .localhost.com as the code below shows:
import {HOSTNAME, isDevelopment} from '@/lib/const'
import {Database} from '@/supabase/database.types'
import {createServerClient} from '@supabase/ssr'
import {cookies} from 'next/headers'
export const createClient = () => {
const cookieStore = cookies()
return createServerClient<Database>(
process.env.NEXT_PUBLIC_SUPABASE_URL!,
process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!,
{
cookieOptions: {
domain: isDevelopment ? '.localhost.com' : HOSTNAME,
},
cookies: {
getAll() {
return cookieStore.getAll()
},
setAll(cookiesToSet) {
try {
cookiesToSet.forEach(({name, value, options}) => {
cookieStore.set(name, value, options)
})
} catch (error) {
// The `setAll` method was called from a Server Component.
// This can be ignored if you have middleware refreshing
// user sessions.
}
},
},
}
)
}This works pretty well; however, when the cookie is about to expire, supabase will request the endpoint token?grant_type=refresh to refresh the access token.
Describe the bug
When I set domain to my cookies, something happened: the expiring cookies are not being updated, and new cookies are being set. If I open my console, I will see four cookies:
Then, I will see infinite requests to the token?grant_type=refresh endpoint because the expiring cookies are still there. It will eventually fail, and I will get disconnected...
If I don't set any domain, this works well.
I can tell that this bug also happened in the production environment on my supabase paid instance.
Here's my middleware code for reference:
import {createServerClient} from '@supabase/ssr'
import {NextRequest, NextResponse} from 'next/server'
import {HOSTNAME, isDevelopment} from './lib/const'
export default async function middleware(request: NextRequest) {
let response = NextResponse.next({
request: {
headers: request.headers,
},
})
const supabase = createServerClient(
process.env.NEXT_PUBLIC_SUPABASE_URL!,
process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!,
{
cookies: {
getAll() {
return request.cookies.getAll()
},
setAll(cookiesToSet) {
cookiesToSet.forEach(({name, value, options}) =>
response.cookies.set(name, value, options)
)
},
},
}
)
await supabase.auth.getUser()
const url = new URL(request.url)
const hostname = request.headers.get('host')
const searchParams = url.searchParams.toString()
const path = `${url.pathname}${searchParams.length > 0 ? `?${searchParams}` : ''}`
// rewrites for app pages
if (hostname === `app.${HOSTNAME}`) {
response = NextResponse.rewrite(new URL(`/app${path === '/' ? '' : path}`, request.url))
}
// rewrite root application to `/home` folder
else if (hostname === HOSTNAME || hostname === `www.${HOSTNAME}`) {
response = NextResponse.rewrite(new URL(`/home${path === '/' ? '' : path}`, request.url))
}
// rewrite everything else to `/[domain]/[slug] dynamic route
else {
response = NextResponse.rewrite(new URL(`/${hostname}${path}`, request.url))
}
return response
}
export const config = {
matcher: [
/*
* Match all paths except for:
* 1. /api routes
* 2. /_next (Next.js internals)
* 3. /_static (inside /public)
* 4. all root files inside /public (e.g. /favicon.ico)
*/
'/((?!api/|_next/|_static/|_vercel|[\\w-]+\\.\\w+).*)',
],
}
To Reproduce
- Add a domain name where cookies are being set
- In your supabase authentication settings, set the Access token (JWT) expiry time to 180seconds, for example
- Login with a user account
- After a minute, supabase will send a request to
token?grant_type=refresh - When opening your console, go to Applications > Cookies. Notice duplicate cookies
- Supabase will try to keep refreshing the cookies, and
token?grant_type=refreshendpoint will kept being requested.
Expected behavior
Cookies should be updated and works seamlessly.
Thank you for your help!
-
OS: MacOS Sonoma 14.1
-
Browser (if applies) Arc browser
"@supabase/ssr": "^0.5.1",
"@supabase/supabase-js": "^2.45.5",