I am working on integrating OAuth in my Next.js project using Supabase and "@supabase/ssr". I've successfully implemented MagicLink and email authentication, but I'm facing issues with OAuth. The authentication process seems to halt unexpectedly when I try to sign in using a social provider like Google.
async function signInWithEmail(formData: FormData) {
"use server"
const origin = headers().get("origin")
const email = formData.get("email") as string
const cookieStore = cookies()
const supabase = createClient(cookieStore)
const { error } = await supabase.auth.signInWithOtp({
email: email,
options: {
emailRedirectTo: `${origin}/auth/callback`,
},
})
if (error) {
console.error(error)
return redirect("/login?message=Could not authenticate user")
}
redirect("/login?message=Check your email inbox to continue signing in")
}
with this callback:
import { createClient } from "@/lib/supabase/server"
import { NextResponse } from "next/server"
import { cookies } from "next/headers"
export async function GET(request: Request) {
const requestUrl = new URL(request.url)
const code = requestUrl.searchParams.get("code")
if (code) {
const cookieStore = cookies()
const supabase = createClient(cookieStore)
await supabase.auth.exchangeCodeForSession(code)
}
return NextResponse.redirect(requestUrl.origin)
}
lib/supabase/server.ts:
import { createServerClient, type CookieOptions } from "@supabase/ssr"
import { cookies } from "next/headers"
export const createClient = (cookieStore: ReturnType<typeof 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) {
console.error(error)
}
},
remove(name: string, options: CookieOptions) {
try {
cookieStore.set({ name, value: "", ...options })
} catch (error) {
console.error(error)
}
},
},
}
)
}
This is the function I'm trying to use to get Oauth to work:
async function signInWithSocialProvider(provider: any) {
"use server"
const origin = headers().get("origin")
const cookieStore = cookies()
const supabase = createClient(cookieStore)
const { error } = await supabase.auth.signInWithOAuth({
provider: provider,
options: {
redirectTo: `${origin}/auth/callback`,
},
})
if (error) {
console.error(error)
return redirect("/login?message=Could not authenticate user")
}
}
Questions:
Is there something I'm missing in the OAuth setup with Supabase and SSR?
Could there be a configuration issue within Supabase or in my Next.js setup causing this behavior?
Any insights or suggestions to resolve this issue would be greatly appreciated.
Expected Behavior: After choosing to sign in with a social provider (e.g., Google), I expect to be redirected to the provider's sign-in page and then back to my application with the user authenticated.
Actual Behavior: The authentication process does not proceed beyond the initial OAuth request. When I log the name and value in the set function within createServerClient, I receive a token, but there's no redirection to the Google sign-in page, and the authentication does not complete.
Logs:
Name: sb-mlirbfytwbmtpcchmvlr-auth-token-code-verifier
Value: "d8d738ef35947d057b013bb19adaee03e44d74003c47ea27b8426b59df264ece2a9f98f78fbdfc5d3e562f021bdf0e0460b633246e889b6c"
Solution:
Adding redirect(data.url)
as the last line within the signInWithSocialProvider function solved the issue. Here is the full function:
async function signInWithSocialProvider(provider: any) {
"use server"
const origin = headers().get("origin")
const cookieStore = cookies()
const supabase = createClient(cookieStore)
const { data, error } = await supabase.auth.signInWithOAuth({
provider: provider,
options: {
redirectTo: `${origin}/auth/callback`,
},
})
if (error) {
console.error(error)
return redirect("/login?message=Could not authenticate user")
}
redirect(data.url)
}
There is no way for the redirect to happen automatically on the server as each server-side framework has a different way of handling redirects. In the browser there is only one API to redirect so this can be hardcoded into the supabase-js library. You will need to get the data
property back from the function and redirect to the data.url
with the method Next.js provides for redirecting. You can read more here https://github.com/orgs/supabase/discussions/15862