Supabase Google OAuth setup (and what to check when it isn't working)
To add Google sign-in to a Supabase web app, create a "Web application" OAuth client in Google Cloud whose only authorized redirect URI is your Supabase callback, https://<project-ref>.supabase.co/auth/v1/callback, then paste its Client ID and Client Secret into the Google provider in Supabase.
Your app's own URLs never go into Google's redirect list: they go into Supabase's Site URL and Redirect URLs, and your code calls supabase.auth.signInWithOAuth({ provider: 'google' }).
How the redirects fit together
There are two separate hops, and most setup mistakes come from mixing them up:
- Google → Supabase. Google sends the user back to Supabase Auth at
https://<project-ref>.supabase.co/auth/v1/callback. This is the URL Google checks against the client's Authorized redirect URIs. If it doesn't match, Google showsredirect_uri_mismatch. - Supabase → your app. Supabase then sends the user to the
redirectToyou passed, as long as it matches the Redirect URLs allow list. With noredirectTo, Supabase uses the Site URL.
So Google only ever needs to know about Supabase's callback. Preview URLs, localhost:3000 and your production domain are all handled on the Supabase side.
Step 1: Configure the Google Auth Platform
In the Google Auth Platform console (as of Oct 2026), pick or create a Google Cloud project, then:
- Branding: set the app name, support email and links to your privacy policy and terms. Google only shows your app name on the consent screen after brand verification (see why Google shows the wrong app name).
- Audience: choose External for public apps. While the app is in Testing, Google limits access to listed test users, with an exception for apps that request only basic sign-in scopes (name, email, profile).
- Data Access (Scopes): add
openidmanually..../auth/userinfo.emailand.../auth/userinfo.profileare added by default. Adding sensitive or restricted scopes can trigger a long Google review.
Step 2: Create the OAuth client ID
In Clients → Create client (as of Oct 2026):
- Application type: Web application.
- Authorized JavaScript origins: your app's origin with no path, for example
https://example.com(nothttps://example.com/app). Addhttp://localhost:3000(or your dev port) while developing, and remove it before going to production. - Authorized redirect URIs: copy the callback URL shown on the Google provider page in the Supabase dashboard. It has this shape:
https://<project-ref>.supabase.co/auth/v1/callback
For the local Supabase CLI stack, also add:
http://127.0.0.1:54321/auth/v1/callback
- Click Create and copy the Client ID and Client Secret.
Google's redirect URIs must use HTTPS (localhost is exempt) and cannot contain wildcards. Google also notes that changes to these settings can take 5 minutes to a few hours to take effect.
Step 3: Turn on the Google provider in Supabase
Hosted project (dashboard): open the Google provider page under Authentication in the Supabase dashboard (as of Oct 2026), enable it, paste the Client ID and Client Secret, and save.
Local development (Supabase CLI): put the secret in .env and reference it from supabase/config.toml:
[auth.external.google]
enabled = true
client_id = "<your-web-client-id>.apps.googleusercontent.com"
secret = "env(SUPABASE_AUTH_EXTERNAL_GOOGLE_CLIENT_SECRET)"
skip_nonce_check = false
Restart the local stack (supabase stop, then supabase start) so the change is picked up. If you have several client IDs (web, iOS, Android), list them comma-separated with the web client ID first.
Step 4: Set the Site URL and Redirect URLs
On the URL Configuration page in the Supabase dashboard (as of Oct 2026):
- Site URL: change the default
http://localhost:3000to your production URL, for examplehttps://example.com. - Redirect URLs: add every URL you will pass as
redirectTo, for example:
https://example.com/auth/callback
http://localhost:3000/**
Wildcard rules, preview-deployment patterns and config.toml equivalents are covered in Supabase redirect URLs explained.
Step 5: Add the sign-in code (supabase-js v2)
Browser-only app (implicit flow)
If you use createClient from @supabase/supabase-js without server-side rendering, one call is enough. Supabase redirects back to your app with the session.
import { createClient } from '@supabase/supabase-js'
const supabase = createClient(
'https://<project-ref>.supabase.co',
'<your-publishable-key>'
)
export async function signInWithGoogle() {
const { error } = await supabase.auth.signInWithOAuth({
provider: 'google',
options: {
// Must match an entry in Redirect URLs
redirectTo: `${window.location.origin}/`,
},
})
if (error) console.error(error.message)
}
Server-side rendering (PKCE flow, Next.js App Router)
With @supabase/ssr, Supabase returns a code to a callback route that you exchange for a session. Start sign-in from the browser client:
'use client'
import { createClient } from '@/lib/supabase/client' // createBrowserClient helper
export function GoogleButton() {
const onClick = async () => {
const supabase = createClient()
await supabase.auth.signInWithOAuth({
provider: 'google',
options: { redirectTo: `${window.location.origin}/auth/callback` },
})
}
return <button onClick={onClick}>Continue with Google</button>
}
Then handle the code in app/auth/callback/route.ts:
import { NextResponse } from 'next/server'
import { createClient } from '@/lib/supabase/server' // createServerClient helper
export async function GET(request: Request) {
const { searchParams, origin } = new URL(request.url)
const code = searchParams.get('code')
let next = searchParams.get('next') ?? '/'
if (!next.startsWith('/')) next = '/'
if (code) {
const supabase = await createClient()
const { error } = await supabase.auth.exchangeCodeForSession(code)
if (!error) {
const forwardedHost = request.headers.get('x-forwarded-host')
const isLocal = process.env.NODE_ENV === 'development'
if (isLocal) return NextResponse.redirect(`${origin}${next}`)
if (forwardedHost) return NextResponse.redirect(`https://${forwardedHost}${next}`)
return NextResponse.redirect(`${origin}${next}`)
}
}
return NextResponse.redirect(`${origin}/auth/auth-code-error`)
}
Remember to add https://example.com/auth/callback (and your local equivalent) to Redirect URLs.
How to confirm it worked
- Click your Google button and look at the address bar on the Google screen. The
redirect_uriquery parameter should be your Supabase callback,https://<project-ref>.supabase.co/auth/v1/callback. - After choosing an account, you should land on your
redirectToURL (or/auth/callback, then your app), not onlocalhost. - Call
supabase.auth.getUser()and check that it returns the Google account's email. The user also appears under Authentication → Users in the dashboard (as of Oct 2026).
Supabase Google OAuth not working: checklist
| Symptom | Likely cause | Fix |
|---|---|---|
Google shows redirect_uri_mismatch |
The Supabase callback isn't in the client's Authorized redirect URIs, or you edited a different client ID | Paste the exact callback from the Supabase Google provider page into the client whose ID is saved in Supabase. See redirect_uri_mismatch. |
Supabase returns error code provider_disabled |
The Google provider is off in Supabase (or in config.toml locally) |
Enable it and save the Client ID and Secret (Step 3). |
Login works but lands on http://localhost:3000 in production |
Site URL still set to localhost, or redirectTo not in Redirect URLs |
See Supabase Google OAuth redirects to localhost. |
Callback route gets ?code= but no session; flow_state_not_found or flow_state_expired |
The PKCE flow state is gone: the code verifier wasn't stored where the server can read it, or the code was already used (codes are single-use and valid for 5 minutes) | Use the @supabase/ssr clients, which keep auth state in cookies, and sign in again rather than reloading the callback URL. |
Error getting user email from external provider |
Some Google Workspace setups need the email scope requested explicitly | Pass scopes: 'https://www.googleapis.com/auth/userinfo.email' in signInWithOAuth options. |
| Change made in Google Cloud but nothing changed | Google settings can take 5 minutes to a few hours to apply | Wait, then retry in a private window. |
Google's sign-in screen names <project-ref>.supabase.co |
That is the Supabase callback domain | See Supabase Google sign-in with a custom domain. |
FAQ
What redirect URI do I put in Google Cloud for Supabase?
Only the Supabase Auth callback: https://<project-ref>.supabase.co/auth/v1/callback, copied from the Google provider page in the Supabase dashboard. For the local CLI stack, add http://127.0.0.1:54321/auth/v1/callback. Your app's own URLs belong in Supabase's Redirect URLs, not in Google Cloud.
Where do I find the Supabase Google OAuth client ID?
You create it yourself in Google Cloud: Google Auth Platform → Clients → Create client → Web application. Copy the Client ID and Client Secret from there into the Google provider settings in Supabase.
Do I need Authorized JavaScript origins?
Supabase's guide asks you to add your app's origin (for example https://example.com, plus http://localhost:<port> during development, which it says to remove when the app goes into production). They matter most if you also use Google's pre-built button or One Tap, which run in the browser and are checked against registered origins.
Why does Google show my Supabase project URL instead of my app name?
Google shows your app name only after brand verification, and the domain shown is the Supabase callback host. A Supabase custom domain changes the domain; brand verification changes the name.
Can I get Google's own access and refresh tokens?
Yes. Pass queryParams: { access_type: 'offline', prompt: 'consent' } in signInWithOAuth options, then read provider_token and provider_refresh_token from the session returned by the sign-in (implicit flow) or by exchangeCodeForSession (PKCE flow).
Sources
- Login with Google | Supabase Docs
- Redirect URLs | Supabase Docs
- PKCE flow | Supabase Docs
- Creating a Supabase client for SSR | Supabase Docs
- Error codes | Supabase Docs
- Google Auth fails for some users | Supabase Docs
- CLI configuration reference | Supabase Docs
- Using OAuth 2.0 for Web Server Applications | Google for Developers
- Manage OAuth Clients | Google Cloud Platform Console Help
- Manage App Audience | Google Cloud Platform Console Help
- Manage OAuth App Branding | Google Cloud Platform Console Help
How this page was made: drafted with AI from the sources listed, reviewed by Pewterkit. Docs checked Oct 27, 2026. Spotted something out of date? Tell us.