Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

"supabase.auth.getUser()" is returning a null user value in nextjs middleware.ts using @supabase/supabase-js @supabase/ssr only #24194

Open
2 tasks done
kritik-sah opened this issue May 5, 2024 · 3 comments
Labels
bug Something isn't working

Comments

@kritik-sah
Copy link

kritik-sah commented May 5, 2024

Bug report

  • I confirm this is a bug with Supabase, not with my own application.
  • I confirm I have searched the Docs, GitHub Discussions, and Discord.

Describe the bug

 const { data, error } = await supabase.auth.getUser();
  console.log("user : ", error); //getting an error 

error, even if I followed everything in doc. https://supabase.com/docs/guides/auth/server-side/nextjs

[AuthSessionMissingError: Auth session missing!] {
  __isAuthError: true,
  name: 'AuthSessionMissingError',
  status: 400,
  code: undefined
}

my observation:

const supabase = createServerClient(
    process.env.NEXT_PUBLIC_SUPABASE_URL!,
    process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!,
    {
      cookies: {
        get(name: string) {
          console.log("name ==>", name);
          console.log("nameValue ==>", request.cookies.get(name)?.value);
          return request.cookies.get(name)?.value;
        },
        set(name: string, value: string, options: CookieOptions) {
          request.cookies.set({
            name,
            value,
            ...options,
          });
          response = NextResponse.next({
            request: {
              headers: request.headers,
            },
          });
          response.cookies.set({
            name,
            value,
            ...options,
          });
        },
        remove(name: string, options: CookieOptions) {
          request.cookies.set({
            name,
            value: "",
            ...options,
          });
          response = NextResponse.next({
            request: {
              headers: request.headers,
            },
          });
          response.cookies.set({
            name,
            value: "",
            ...options,
          });
        },
      },
    }
  );

logs:

name ==> sb-yelbdeiefeqnignhtxkc-auth-token
nameValue ==> undefined
name ==> sb-yelbdeiefeqnignhtxkc-auth-token.0
nameValue ==> undefined

real name of cookie is something different
Screenshot 2024-05-05 132915

I am using Google and github as provider. and this is what my code look like full repo an opensource portfolio & resume builder

src/middleware.ts

import { updateSession } from "@/utils/supabase/middleware";
import { type NextRequest } from "next/server";

export async function middleware(request: NextRequest) {
  return await updateSession(request);
}

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|p|.*\\.(?:svg|png|jpg|jpeg|gif|webp)$).*)",
  ],
};

src\utils\supabase\client.ts

import { createBrowserClient } from "@supabase/ssr";

export function createClient() {
  return createBrowserClient(
    process.env.NEXT_PUBLIC_SUPABASE_URL!,
    process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!
  );
}

src\utils\supabase\server.ts

"use server";
import { createServerClient, type CookieOptions } from "@supabase/ssr";
import { cookies } from "next/headers";

export default async function createClient() {
  const cookieStore = cookies();

  return createServerClient(
    process.env.NEXT_PUBLIC_SUPABASE_URL!,
    process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!,
    {
      cookies: {
        get(name: string) {
          return cookieStore.get(name)?.value;
        },
        set(name: string, value: string, options: CookieOptions) {
          try {
            cookieStore.set({ name, value, ...options });
          } catch (error) {
            // The `set` method was called from a Server Component.
            // This can be ignored if you have middleware refreshing
            // user sessions.
          }
        },
        remove(name: string, options: CookieOptions) {
          try {
            cookieStore.set({ name, value: "", ...options });
          } catch (error) {
            // The `delete` method was called from a Server Component.
            // This can be ignored if you have middleware refreshing
            // user sessions.
          }
        },
      },
    }
  );
}

src\utils\supabase\middleware.ts

import { createServerClient, type CookieOptions } from "@supabase/ssr";
import { NextResponse, type NextRequest } from "next/server";

export async function updateSession(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: {
        get(name: string) {
          console.log("name ==>", name);
          console.log("nameValue ==>", request.cookies.get(name)?.value);
          return request.cookies.get(name)?.value;
        },
        set(name: string, value: string, options: CookieOptions) {
          request.cookies.set({
            name,
            value,
            ...options,
          });
          response = NextResponse.next({
            request: {
              headers: request.headers,
            },
          });
          response.cookies.set({
            name,
            value,
            ...options,
          });
        },
        remove(name: string, options: CookieOptions) {
          request.cookies.set({
            name,
            value: "",
            ...options,
          });
          response = NextResponse.next({
            request: {
              headers: request.headers,
            },
          });
          response.cookies.set({
            name,
            value: "",
            ...options,
          });
        },
      },
    }
  );

  const { data, error } = await supabase.auth.getUser();
  console.log("user : ", error);

  // refreshing the auth token
  const {
    data: { user },
  } = await supabase.auth.getUser();
  if (
    !user &&
    request.nextUrl.pathname !== "/signin" &&
    request.nextUrl.pathname !== "/"
  ) {
    return NextResponse.redirect(new URL("/signin", request.url));
  }
  return NextResponse.next({
    request: {
      headers: request.headers,
    },
  });
}

src\app\auth\callback\route.ts

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

export async function GET(request: Request) {
  const { searchParams, origin } = new URL(request.url);
  const code = searchParams.get("code");
  // if "next" is in param, use it as the redirect URL
  const next = searchParams.get("next") ?? "/";

  if (code) {
    const cookieStore = cookies();
    const supabase = createServerClient(
      process.env.NEXT_PUBLIC_SUPABASE_URL!,
      process.env.NEXT_PUBLIC_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.delete({ name, ...options });
          },
        },
      }
    );
    const { error } = await supabase.auth.exchangeCodeForSession(code);
    if (!error) {
      return NextResponse.redirect(`${origin}${next}`);
    }
  }

  // return the user to an error page with instructions
  return NextResponse.redirect(`${origin}/auth/auth-code-error`);
}

onClick function signinWithSocial("google" | "github")

async function signinWithSocial(provider: Provider) {
    const supabase = await createClient();
    const { data, error } = await supabase.auth.signInWithOAuth({
      provider: provider,
      options: {
        redirectTo: `${location.origin}/auth/callback?next=${location.origin}/app`,
      },
    });
    if (error) {
      console.error(error);
    }
    console.log(data);
  }

To Reproduce

Steps to reproduce the behavior, please provide code snippets or a repository:

  1. Go to https://supabase.com/docs/guides/auth/server-side/nextjs follow the guide
  2. use google social login
  3. check the user value in middleware its null
  4. See error

Expected behavior

in the middleware i should get the user value, by which i can check and redirect someone if they are not loged in

Screenshots

If applicable, add screenshots to help explain your problem.

System information

  • OS: [ Windows]
  • Browser (if applies) [brave]
  • Version of supabase-js:
  • "@supabase/ssr": "^0.3.0",
    "@supabase/supabase-js": "^2.43.1",
  • Version of Node.js: [v20.11.0]

Additional context

I have setuped oauth provider in supabase dashboard successfully, so that wont be any problem

@kritik-sah kritik-sah added the bug Something isn't working label May 5, 2024
@simonha9
Copy link
Contributor

simonha9 commented May 6, 2024

Hi! Is there a specific reason why calling auth.getUser() in your protected route to see if they are logged in and then kicking them out is not an option? It seems like the guide you linked does exactly that in the last step. afaik there won't be a user before a code exchange is done, which looks like that is the case in the attached picture because I only see the code challenge.

@d-e-h-i-o
Copy link

We're also experiencing a similar problem. On our server, we're having the following check:

    const authenticatedUser = await this.supabaseAdminClient.auth.getUser(jwtToken)
    if (!authenticatedUser.data.user) {
      this.logger.debug('No user is associated with the access token!')
      return false
    }

However, sometimes, even though we are using a valid jwt, await this.supabaseAdminClient.auth.getUser(jwtToken) is returning null.

"@supabase/supabase-js": "^2.39.8"

@aaa3334
Copy link

aaa3334 commented May 20, 2024

Think this is the same issue I reported here:
#22719

Logging in twice gets it to set - somoeone suggested the set method is only setting one cookie at a time...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

4 participants