I am not getting supabase user session cookies, even after ignoring hmr and .well-known endpoints
import { createServerClient } from "@supabase/ssr";
import { NextResponse, type NextRequest } from "next/server";
const publicRoutes = ["/", "/:slug"];
const protectedRoutes = ["/form", "/username"];
export async function updateSession(request: NextRequest) {
let supabaseResponse = NextResponse.next({
request,
});
const path = request.nextUrl.pathname
if (path.startsWith('/.well-known') || path.startsWith('/_next')) {
return supabaseResponse
}
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)
);
},
},
}
);
console.log("Incoming cookies:", request.cookies.getAll())
const {
data: { user },
} = await supabase.auth.getUser();
console.log("path- :- " + path )
console.log("user- :- " + user )
if(!user){
if (protectedRoutes.includes(path) || (!publicRoutes.includes(path) && !path.match(/^\/[^/]+$/))) {
const url = request.nextUrl.clone()
url.pathname = '/'
return NextResponse.redirect(url)
}
if (user && path === '/') {
const url = request.nextUrl.clone()
url.pathname = '/form'
return NextResponse.redirect(url)
}
}
return supabaseResponse;
}
import { createServerClient } from "@supabase/ssr";
import { NextResponse, type NextRequest } from "next/server";
const publicRoutes = ["/", "/:slug"];
const protectedRoutes = ["/form", "/username"];
export async function updateSession(request: NextRequest) {
let supabaseResponse = NextResponse.next({
request,
});
const path = request.nextUrl.pathname
if (path.startsWith('/.well-known') || path.startsWith('/_next')) {
return supabaseResponse
}
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)
);
},
},
}
);
console.log("Incoming cookies:", request.cookies.getAll())
const {
data: { user },
} = await supabase.auth.getUser();
console.log("path- :- " + path )
console.log("user- :- " + user )
if(!user){
if (protectedRoutes.includes(path) || (!publicRoutes.includes(path) && !path.match(/^\/[^/]+$/))) {
const url = request.nextUrl.clone()
url.pathname = '/'
return NextResponse.redirect(url)
}
if (user && path === '/') {
const url = request.nextUrl.clone()
url.pathname = '/form'
return NextResponse.redirect(url)
}
}
return supabaseResponse;
}
Incoming cookies: [ { name: '__next_hmr_refresh_hash__', value: '264' } ]
path- :- /
user- :- null
Incoming cookies: [ { name: '__next_hmr_refresh_hash__', value: '264' } ]
path- :- /
user- :- null
"@supabase/ssr": "^0.7.0",
"@supabase/supabase-js": "^2.57.4",
"@supabase/ssr": "^0.7.0",
"@supabase/supabase-js": "^2.57.4",
posted in comments
posted in comments
6 Replies
Since the post got "too long" for word count, here's the problem
-
I am supposed to get cookies when I am redirected from oAuth to the page. Since I only want authorized users to see that page I implemented a middleware function to check the user's authorization.
But I am unable to do that. The user is returning null, even when logged in. According to a github thread, it was an issue with the cookies being sent, and when I console.logged the cookies, I only saw nextjs hot module cookies, no supabase cookies.
I am not sure how to proceed with this.
sb-access-token
sb-access-token
/form
/form
Github thread - https://github.com/supabase/supabase/issues/24194#issuecomment-2725577116
but the difference is, in his case he is getting the access token cookies, I am not getting them at all
GitHub
"supabase.auth.getUser()" is returning a null user value in nextjs ...
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 su...
Please check this.
It always works.
https://supabase.com/docs/guides/auth/server-side/nextjs
Yeah, that's where I copied the code from, it's not working, even when I paste as it is
Here's my code almost 95% same, just changed the path names and added console statements, that's it. But doesn't work
import { createServerClient } from "@supabase/ssr";
import { NextResponse, type NextRequest } from "next/server";
export async function updateSession(request: NextRequest) {
let supabaseResponse = NextResponse.next({
request,
});
const path = request.nextUrl.pathname;
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();
console.log("path - " + path);
console.log("User - " + user);
console.log(request.cookies.getAll());
if (!user && request.nextUrl.pathname === "/form") {
// no user, potentially respond by redirecting the user to the login page
const url = request.nextUrl.clone();
url.pathname = "/";
return NextResponse.redirect(url);
}
return supabaseResponse;
}
import { createServerClient } from "@supabase/ssr";
import { NextResponse, type NextRequest } from "next/server";
export async function updateSession(request: NextRequest) {
let supabaseResponse = NextResponse.next({
request,
});
const path = request.nextUrl.pathname;
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();
console.log("path - " + path);
console.log("User - " + user);
console.log(request.cookies.getAll());
if (!user && request.nextUrl.pathname === "/form") {
// no user, potentially respond by redirecting the user to the login page
const url = request.nextUrl.clone();
url.pathname = "/";
return NextResponse.redirect(url);
}
return supabaseResponse;
}
could you please share your code for auth?
login.tsx (this is in "/") root
My social login is working, it's saving the token in localStorage but this flow sends me to an error page and doesn't save the token in cookies
Silly Mistake -
in login.tsx
import { supabase } from "../../lib/supabase-client";
should've been
import { createClient } from "@/utils/supabase/client";
import from utils/supabase/client NOT supabase/server and ensure it's supabase/ssr not js
Going to keep this up in case anyone makes the same mistake I made
I don't know how to mark it resolved
"use client";
import { redirect } from "next/navigation";
import { supabase } from "../../lib/supabase-client";
import LogoutBtn from "../auth/session/logout";
import { UserAuthContext } from "../hooks/authContext";
import { useContext } from "react";
export default function Login() {
const handleLogin = async () => {
const { data, error } = await supabase.auth.signInWithOAuth({
provider: "google",
options: {
redirectTo: "http://localhost:3000/auth/callback",
},
});
if (data.url) {
redirect(data.url);
}
};
const userAuthenticated = useContext(UserAuthContext);
const btnclass =
"border-1 p-2 pl-4 pr-4 cursor-pointer rounded-2xl hover:bg-gray-800 active:bg-gray-600 ";
return (
<>
<div>
{" "}
{/*Master Div */}
<div className="text-center">
<h1 className="mt-20 text-4xl">Best way </h1>
<h3 className="text-2xl italic">
Login {">"} create {">"} Publish. That's it!
</h3>
</div>
<div className="mx-auto w-[40vw] h-fit p-16 mt-10 flex flex-col items-center justify-center rounded-4xl bg-[#171717]">
<div className="flex flex-col items-center">
<h1 className="text-3xl mb-10">Get started!</h1>
</div>
{!userAuthenticated && (
<button className={`${btnclass} pb-4`} onClick={handleLogin}>
Continue with Google
</button>
)}
{userAuthenticated && <LogoutBtn />}
</div>
</div>
{/*Master Div */}
</>
);
}
"use client";
import { redirect } from "next/navigation";
import { supabase } from "../../lib/supabase-client";
import LogoutBtn from "../auth/session/logout";
import { UserAuthContext } from "../hooks/authContext";
import { useContext } from "react";
export default function Login() {
const handleLogin = async () => {
const { data, error } = await supabase.auth.signInWithOAuth({
provider: "google",
options: {
redirectTo: "http://localhost:3000/auth/callback",
},
});
if (data.url) {
redirect(data.url);
}
};
const userAuthenticated = useContext(UserAuthContext);
const btnclass =
"border-1 p-2 pl-4 pr-4 cursor-pointer rounded-2xl hover:bg-gray-800 active:bg-gray-600 ";
return (
<>
<div>
{" "}
{/*Master Div */}
<div className="text-center">
<h1 className="mt-20 text-4xl">Best way </h1>
<h3 className="text-2xl italic">
Login {">"} create {">"} Publish. That's it!
</h3>
</div>
<div className="mx-auto w-[40vw] h-fit p-16 mt-10 flex flex-col items-center justify-center rounded-4xl bg-[#171717]">
<div className="flex flex-col items-center">
<h1 className="text-3xl mb-10">Get started!</h1>
</div>
{!userAuthenticated && (
<button className={`${btnclass} pb-4`} onClick={handleLogin}>
Continue with Google
</button>
)}
{userAuthenticated && <LogoutBtn />}
</div>
</div>
{/*Master Div */}
</>
);
}
route.ts
route.ts
import { NextResponse } from 'next/server'
// The client you created from the Server-Side Auth instructions
import { createClient } from '@/utils/supabase/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
let next = searchParams.get('next') ?? '/'
if (!next.startsWith('/')) {
// if "next" is not a relative URL, use the default
next = '/'
}
if (code) {
const supabase = await createClient()
const { error } = await supabase.auth.exchangeCodeForSession(code)
if (!error) {
const forwardedHost = request.headers.get('x-forwarded-host') // original origin before load balancer
const isLocalEnv = process.env.NODE_ENV === 'development'
if (isLocalEnv) {
// we can be sure that there is no load balancer in between, so no need to watch for X-Forwarded-Host
return NextResponse.redirect(`${origin}${next}`)
} else if (forwardedHost) {
return NextResponse.redirect(`https://${forwardedHost}${next}`)
} else {
return NextResponse.redirect(`${origin}${next}`)
}
}
}
// return the user to an error page with instructions
return NextResponse.redirect(`${origin}/auth/auth-code-error`)
}
import { NextResponse } from 'next/server'
// The client you created from the Server-Side Auth instructions
import { createClient } from '@/utils/supabase/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
let next = searchParams.get('next') ?? '/'
if (!next.startsWith('/')) {
// if "next" is not a relative URL, use the default
next = '/'
}
if (code) {
const supabase = await createClient()
const { error } = await supabase.auth.exchangeCodeForSession(code)
if (!error) {
const forwardedHost = request.headers.get('x-forwarded-host') // original origin before load balancer
const isLocalEnv = process.env.NODE_ENV === 'development'
if (isLocalEnv) {
// we can be sure that there is no load balancer in between, so no need to watch for X-Forwarded-Host
return NextResponse.redirect(`${origin}${next}`)
} else if (forwardedHost) {
return NextResponse.redirect(`https://${forwardedHost}${next}`)
} else {
return NextResponse.redirect(`${origin}${next}`)
}
}
}
// return the user to an error page with instructions
return NextResponse.redirect(`${origin}/auth/auth-code-error`)
}
utils/supabase/server.ts
utils/supabase/server.ts
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.
}
},
},
}
)
}
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.
}
},
},
}
)
}