Closed shawnesquivel closed 5 months ago
Hey! Thanks for reporting this. By default, the auth-helpers and ssr packages use the PKCE auth flow, which requires you to redirect to a code exchange route after the authentication process has completed. You will need a route to handle this exchange, like this:
// /auth/callback.ts
import { cookies } from 'next/headers'
import { NextResponse } from 'next/server'
import { type CookieOptions, createServerClient } from '@supabase/ssr'
export async function GET(request: Request) {
const { searchParams } = new URL(request.url)
const code = searchParams.get('code')
if (code) {
const cookieStore = cookies()
const supabase = createServerClient(...)
const { error } = await supabase.auth.exchangeCodeForSession(code)
if (!error) {
// change this to wherever you want to redirect the user after authentication completes
return NextResponse.redirect('http://localhost:3000/dashboard')
}
}
// return the user to an error page with instructions
return NextResponse.redirect('http://localhost:3000/auth/error')
}
Then your call to signInWithOAuth
needs to redirect to the above Route Handler.
const googleRes = await supabase.auth.signInWithOAuth({
provider: "google",
options: {
redirectTo: "http://localhost:3000/auth/callback",
},
});
The best place to start with a Next.js and Supabase app is the with-supabase template. This already has server-side authentication configured, so you can just focus on building an awesome app!
You can use this with the create-next-app
command like this:
npx create-next-app@latest -e with-supabase
similiar error here, with latest supabase(self hosted) when trying keycloak oauth: `
⨯ AuthApiError: invalid flow state, no valid flow state found at handleError (webpack-internal:///(rsc)/./node_modules/.pnpm/@supabase+auth-js@2.63.0/node_modules/@supabase/auth-js/dist/module/lib/fetch.js:74:11) at process.processTicksAndRejections (node:internal/process/task_queues:95:5) at async _handleRequest (webpack-internal:///(rsc)/./node_modules/.pnpm/@supabase+auth-js@2.63.0/node_modules/@supabase/auth-js/dist/module/lib/fetch.js:120:9) at async _request (webpack-internal:///(rsc)/./node_modules/.pnpm/@supabase+auth-js@2.63.0/node_modules/@supabase/auth-js/dist/module/lib/fetch.js:99:18) at async SupabaseAuthClient._exchangeCodeForSession (webpack-internal:///(rsc)/./node_modules/.pnpm/@supabase+auth-js@2.63.0/node_modules/@supabase/auth-js/dist/module/GoTrueClient.js:417:33) at async eval (webpack-internal:///(rsc)/./node_modules/.pnpm/@supabase+auth-js@2.63.0/node_modules/@supabase/auth-js/dist/module/GoTrueClient.js:744:28) { __isAuthError: true, status: 404, code: 'flow_state_not_found' } GET /auth/callback?state=xxx&session_state=xxx&code=xxx 500 in 426070ms`
similiar error here, with latest supabase(self hosted) when trying keycloak oauth: `
⨯ AuthApiError: invalid flow state, no valid flow state found at handleError (webpack-internal:///(rsc)/./node_modules/.pnpm/@supabase+auth-js@2.63.0/node_modules/@supabase/auth-js/dist/module/lib/fetch.js:74:11) at process.processTicksAndRejections (node:internal/process/task_queues:95:5) at async _handleRequest (webpack-internal:///(rsc)/./node_modules/.pnpm/@supabase+auth-js@2.63.0/node_modules/@supabase/auth-js/dist/module/lib/fetch.js:120:9) at async _request (webpack-internal:///(rsc)/./node_modules/.pnpm/@supabase+auth-js@2.63.0/node_modules/@supabase/auth-js/dist/module/lib/fetch.js:99:18) at async SupabaseAuthClient._exchangeCodeForSession (webpack-internal:///(rsc)/./node_modules/.pnpm/@supabase+auth-js@2.63.0/node_modules/@supabase/auth-js/dist/module/GoTrueClient.js:417:33) at async eval (webpack-internal:///(rsc)/./node_modules/.pnpm/@supabase+auth-js@2.63.0/node_modules/@supabase/auth-js/dist/module/GoTrueClient.js:744:28) { __isAuthError: true, status: 404, code: 'flow_state_not_found' } GET /auth/callback?state=xxx&session_state=xxx&code=xxx 500 in 426070ms`
Found something weird: My nextjs app works fine with supabase instance deploy on supabase.com, but when I switch to use a self-hosted instance, it gives me this error.
I debugged step by step and found the only different is the code
parameter called with /auth/callback
, code Self-hosted version is something like '3ccfedb0-142a-4f95-a50c-d496f02b577c.704c8b6e-0761-4a26-a365-26689fb80fcb.d650aec2-a988-49ac-a63f-670ba6959540', which is not 'uuid.NewV4()'.
Notice the code param
GET /auth/callback?state=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE3MTMyNzk5MjAsInNpdGVfdXJsIjoiaHR0cHM6Ly9leHBsb3JhdGlvbi5sb2NhbC5kcC50ZWNoIiwiaWQiOiIwMDAwMDAwMC0wMDAwLTAwMDAtMDAwMC0wMDAwMDAwMDAwMDAiLCJmdW5jdGlvbl9ob29rcyI6bnVsbCwicHJvdmlkZXIiOiJrZXljbG9hayIsInJlZmVycmVyIjoiaHR0cDovL2xvY2FsaG9zdDozMDAxL2F1dGgvY2FsbGJhY2s_bmV4dD11bmRlZmluZWQiLCJmbG93X3N0YXRlX2lkIjoiYjlkYTA5ZDMtNWIwMy00M2E2LWE2ODktNTQ0ZThmZGNiNTFhIn0.x5lpS-RBfenlwIBFkj76Rn0YxeYp2n5mlBNhs0lrz4c&session_state=704c8b6e-0761-4a26-a365-26689fb80fcb&code=3ccfedb0-142a-4f95-a50c-d496f02b577c.704c8b6e-0761-4a26-a365-26689fb80fcb.d650aec2-a988-49ac-a63f-670ba6959540
After setting this env to auth container, get things working well now.
GOTRUE_EXTERNAL_KEYCLOAK_REDIRECT_URI: https://MY-SUPABASE-HOSTNAME/auth/v1/callback
After setting this env to auth container, get things working well now.
GOTRUE_EXTERNAL_KEYCLOAK_REDIRECT_URI: https://MY-SUPABASE-HOSTNAME/auth/v1/callback
can you elaborate more please ? I'm using a self hosted supabase instance on coolify and integrated azure auth. I'm using nextjs for my app. On the server, this is my code:
`'use server'
import { createClient } from "@/utils/supabase/server"; import { redirect } from "next/navigation";
export async function azureAuth(): Promise
if (data.url) { redirect(data.url) // use the redirect API for your server framework } }`
the flow is working fine and I get to login into my microsoft account, but when the callback url is called with a valid code and state, I get a 500.
I have this redirect uri for the gotrue auth container:
- 'GOTRUE_EXTERNAL_AZURE_REDIRECT_URI=https://myappurl.com/api/auth/azure/callback'
which leads to a nextjs api route with this:
`import { cookies } from 'next/headers' import { NextResponse } from 'next/server' import { type CookieOptions, createServerClient } from '@supabase/ssr'
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
// TODO: implement page
return NextResponse.redirect(${origin}/auth/auth-code-error
)
}
I don't understand the problem here.`
Bug report
Describe the bug
I'm using Supabase Auth helpers. I configured and tested that signing up a user with email/password is good.
However, when trying to set up Google auth, I cannot login my user. This is somewhat related to this unresolved discussion: https://github.com/orgs/supabase/discussions/16743
Tutorial I Followed https://supabase.com/docs/guides/auth/social-login/auth-google#using-the-oauth-flow-for-web
Troubleshooting
code_challenge
parameter, which suggests that Google is authenticating the loginTo Reproduce
I can get the URL from my google auth
which returns a URL with the code_challenge
now back in my main page, if I execute getUser, it returns null.
Expected behavior
supabase.auth.getUser()
returns nullScreenshots
If applicable, add screenshots to help explain your problem.
System information
Full Code
See my full code snippet
```javascript const supabase = createClientComponentClient( NEXT_PUBLIC_SUPABASE_URL, NEXT_PUBLIC_SUPABASE_ANON_KEY ); const handleGoogleSignIn = async () => { try { const googleRes = await supabase.auth.signInWithOAuth({ provider: "google", options: { redirectTo: "http://localhost:3000", }, }); const tokenRes = await passGoogleTokenToSupabase(googleRes); // router.refresh(); } catch (err) { console.error(err); } }; async function passGoogleTokenToSupabase(request) { try { const requestUrl = new URL(request.data.url); const code = requestUrl.searchParams.get("code_challenge"); if (code) { console.log("got the code"); localStorage.setItem("codePassedToExchangeCodeForSesssion", code); const { data, error } = await supabase.auth.exchangeCodeForSession( code ); return data; } else { return null; } } catch (err) { console.error(err); } } ```