supabase / auth-helpers

A collection of framework specific Auth utilities for working with Supabase.
https://supabase.github.io/auth-helpers/
MIT License
902 stars 237 forks source link

SSR: Setting custom name for cookie causes subsequent calls to getUser to fail #719

Closed NickG-NZ closed 8 months ago

NickG-NZ commented 8 months ago

Bug report

Describe the bug

Setting a custom name for the auth-token cookie when using supabase in a server route breaks the authentication system. Specifically, the user can be successfully logged in with supabase.auth.signInWithPassword(...), but any subsqeuent calls to supabase.auth.getUser and supabase.auth.getSession fail. The call to getUser fails with error: AuthError: User not Found

Note this is true even if the call to getSession or getUser is made immediately after the successful call to signIn (ie. the problem is unrelated to how the cookies are set in the browser as it can occur before the server has even responded).

To Reproduce

supabase/ssr 0.0.10, supabase/supabase-js 2.39.3 NextJS 13.5.6 App router

Create a supabase server client in a route-handler as shown here: https://supabase.com/docs/guides/auth/server-side/creating-a-client?environment=route-handler

Add the cookieOptions property to the object passed to createServerClient


import { createServerClient, type CookieOptions } from '@supabase/ssr'
import { NextResponse } from 'next/server'
import { cookies } from 'next/headers'

export async function POST(request: Request) {
  const cookieStore = cookies()

  const supabase = createServerClient(
    process.env.SUPABASE_URL!,
    process.env.SUPABASE_ANON_KEY!,
    {
      cookies: {
        get(name: string) {
          return cookieStore.get(name)?.value
        },
        set(name: string, value: string, options: CookieOptions) {
          cookieStore.set({ name, value, ...options })
        },
        remove(name: string, options: CookieOptions) {
          cookieStore.set({ name, value: '', ...options })
        },
      },
      cookieOptions: {
        name: 'my-access-token-cookie'
      }
    }
  );
  const { email, password } = await request.json();

  const { data, error } = await supabase.auth.signInWithPassword({ email, password });

  if (!error) {
    const { data: userData } = await supabase.auth.getUser();  // this will fail
  }

  return NextResponse.json(null,
    {
      status: 200,
      statusText: 'OK'
    });
}

Call this route-handler

Expected behavior

After creating the supabase server client with createServerClient and passing the cookieOptions object with the property name: 'my-access-token-cookie', supabse auth should be able to login /signup users and immediately authenticate further requests with getSession or getUser.

Note: we are also assuming that the set-cookie header of the server's response will be automatically set following auth.signnWithPassword or auth.signUp and contains a cookie called my-access-token-cookie providing the access and refresh tokens to the client/browser. This doesn't affect the current issue but incredibly is never explicitly stated in the docs even though it is fundamental to how the SSR auth works.

We expect that further requests to the server made with our-access-token-cookie in the headers can be authorized on the server using the supabase server client.

System information

Additional context

We never explicitly call setSession (unlike the example on this page https://supabase.com/docs/guides/auth/server-side-rendering ) and it is unclear why we would ever need it? But we do all our auth on the server side so perhaps it is only needed if calling supabase from the Browser?

kangmingtay commented 8 months ago

hey @NickG-NZ, i've fixed this in #730 so this should work now, can you please try again and let us know if you're still running into any issues?