"supabase.auth.getUser()" is returning a null user value in nextjs middleware.ts using @supabase/supabase-js @supabase/ssr only
Bug report
- [x] I confirm this is a bug with Supabase, not with my own application.
- [x] 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
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:
- Go to https://supabase.com/docs/guides/auth/server-side/nextjs follow the guide
- use google social login
- check the user value in middleware its null
- 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
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.
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"
Think this is the same issue I reported here: https://github.com/supabase/ssr/issues/36
Logging in twice gets it to set - somoeone suggested the set method is only setting one cookie at a time...
Following this, @supabase-automated-user pls look into this
somoeone suggested the set method is only setting one cookie at a time...
This could very well be the case. We're about to release 0.4.0 of @supabase/ssr in the next 24 hours. Please check this discussion: https://github.com/orgs/supabase/discussions/27037 and upgrade as soon as able to use getAll() and setAll(). Docs are here: https://github.com/supabase/supabase/pull/27242
still have an error event update to latest version of @supabase/ssr.
I did a quick fix that solved the error. In the process of sign-in, I save a cookie reference for refresh and access tokens (sb-access-token, sb-refresh-token)
const cookieStore = cookies();
const { data, error } = await repository.auth.signInWithPassword({
email,
password,
});
cookieStore.set('sb-access-token', data?.session?.access_token);
cookieStore.set('sb-refresh-token', data?.session?.refresh_token);
When I try to capture user information in my API routes I've an auxiliary function:
retrieveAuthOrSessionUser = async () => {
let userFinal = null;
const cookieStore = cookies();
const accessToken = cookieStore.get('sb-access-token');
const refreshToken = cookieStore.get('sb-refresh-token');
const {
data: { user },
error,
} = await this.supabase.auth.getUser();
if (error) {
const { data: dataSession } = await this.supabase.auth.setSession({
access_token: accessToken?.value ?? '',
refresh_token: refreshToken?.value ?? '',
});
userFinal = dataSession?.user;
} else {
userFinal = user;
}
const { id } = userFinal ?? {};
return {
id: id ?? '',
};
};
Remember to erase the cookies on the process of sign-out
const supabaseCookies = cookies().getAll();
supabaseCookies.map((cookie) => {
if (cookie.name.includes('sb-')) {
cookies().delete(cookie.name);
}
});
isn't the best scenario or code, but does the job. Hope this Helps.
Same issue, any solutions? Next.js 14.2.5
In my case
removing export const dynamic = 'force-static' from layout resolve issue
Hi all - just checking in here, version 0.5.0 @supabase/ssr was released last week. Are you still experiencing the same issue?
@Hallidayo Yes I'm still experiencing the issue, nextjs version 14.2.6
Hi, just want to report here I am experiencing the same issue.
Currently on ssr 0.5.1 and nextjs version 14.2.14
Experiencing this issue as well - ssr 0.5.1, next 14.2.1
Same issue here, ssr 0.5.1, next 14.2.14