Supabase Auth with Google OAuth: Step-by-Step

By Yanni Papoutsis | 8 min read | 2026-07-05

TL;DR

Supabase Auth supports Google OAuth out of the box. You need three things: a Supabase project, a Google Cloud OAuth 2.0 client, and a few lines of React code calling signInWithOAuth. This guide covers the full setup from creating the Google Cloud credentials to handling the user session in your React app.

Prerequisites

How Supabase Google OAuth Works

The flow is:

  1. User clicks "Sign in with Google" in your app
  2. Your app calls supabase.auth.signInWithOAuth({ provider: 'google' })
  3. Supabase redirects the user to Google's OAuth consent screen
  4. Google authenticates the user and redirects back to your configured callback URL
  5. Supabase exchanges the authorisation code for an access token and creates a session
  6. Your app receives the session via a URL fragment or cookie and logs the user in

You never handle Google credentials directly. Supabase manages the token exchange.

Step 1: Create a Supabase Project

If you do not have a Supabase project yet:

  1. Go to supabase.com and click Start your project.
  2. Log in with GitHub.
  3. Click New project.
  4. Choose an organisation, set a project name, create a strong database password, and select a region close to your users.
  5. Click Create new project and wait approximately two minutes for provisioning.

Once the project is ready, navigate to Project Settings > API. You will need:

Keep these values -- you will use them in Step 5.

Step 2: Configure Google Cloud Console

Google requires you to register your application before granting OAuth access.

Create a Google Cloud Project

  1. Go to console.cloud.google.com.
  2. Click the project dropdown at the top and select New Project.
  3. Name your project (for example, my-app-auth) and click Create.
  4. Wait a few seconds and select your new project from the dropdown.

Enable the Google OAuth API

  1. In the left sidebar, go to APIs and Services > Library.
  2. Search for "Google+ API" or "Identity Platform" -- you do not need to enable a specific API; the OAuth consent screen is sufficient.
  3. Go to APIs and Services > OAuth consent screen.

Configure the OAuth Consent Screen

  1. Choose External for user type (unless you are building an internal Google Workspace app).
  2. Click Create.
  3. Fill in:
  4. App name: Your application's display name (users see this on the consent screen)
  5. User support email: Your email address
  6. Developer contact information: Your email address
  7. Click Save and Continue.
  8. On the Scopes page, click Add or Remove Scopes and add:
  9. openid
  10. email
  11. profile
  12. Click Save and Continue.
  13. On the Test users page, add your own Google email while in development (your app is in "testing" mode until you publish it).
  14. Click Save and Continue, then Back to Dashboard.

Create OAuth 2.0 Credentials

  1. Go to APIs and Services > Credentials.
  2. Click Create Credentials > OAuth client ID.
  3. Select Web application as the application type.
  4. Set Name to something descriptive (for example, my-app-web-client).
  5. Under Authorised JavaScript origins, add your app's URLs: http://localhost:5173 https://yourdomain.com
  6. Under Authorised redirect URIs, add Supabase's callback URL: https://your-project-ref.supabase.co/auth/v1/callback Replace your-project-ref with your actual Supabase project reference (visible in your project URL).
  7. Click Create.

Google will show you a Client ID and Client Secret. Copy both -- you will need them in the next step.

Step 3: Add Google as a Provider in Supabase

  1. Go to your Supabase project dashboard.
  2. In the left sidebar, go to Authentication > Providers.
  3. Scroll down to find Google in the provider list and click to expand it.
  4. Toggle Enable Google provider on.
  5. Paste your Client ID and Client Secret from Google Cloud Console.
  6. Click Save.

Step 4: Configure Redirect URLs in Supabase

Supabase needs to know which URLs are permitted to receive the OAuth callback.

  1. In the Supabase dashboard, go to Authentication > URL Configuration.
  2. Set the Site URL to your production domain: https://yourdomain.com
  3. Under Redirect URLs, add all valid redirect destinations: http://localhost:5173/** https://yourdomain.com/** https://your-project-*.vercel.app/** The ** wildcard matches any path. This is important for preview deployments on Vercel, which have unique subdomains.
  4. Click Save.

If you skip this step, users will see an error after Google redirects back to Supabase: "Redirect URL not allowed."

Step 5: Install and Configure the Supabase Client

In your React project, install the Supabase JavaScript client:

npm install @supabase/supabase-js

Create a Supabase client file at src/lib/supabase.ts:

import { createClient } from '@supabase/supabase-js'

const supabaseUrl = import.meta.env.VITE_SUPABASE_URL
const supabaseAnonKey = import.meta.env.VITE_SUPABASE_ANON_KEY

if (!supabaseUrl || !supabaseAnonKey) {
  throw new Error('Missing Supabase environment variables')
}

export const supabase = createClient(supabaseUrl, supabaseAnonKey)

Add your Supabase credentials to your .env.local file (never commit this file):

VITE_SUPABASE_URL=https://your-project-ref.supabase.co
VITE_SUPABASE_ANON_KEY=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.placeholder

The anon key is safe to expose in front-end code -- it has no write access to your database by default and is protected by Row Level Security policies.

Step 6: Implement signInWithOAuth in React

Create a sign-in button component at src/components/GoogleSignIn.tsx:

import { supabase } from '../lib/supabase'

export function GoogleSignIn() {
  const handleGoogleSignIn = async () => {
    const { error } = await supabase.auth.signInWithOAuth({
      provider: 'google',
      options: {
        redirectTo: `${window.location.origin}/auth/callback`,
      },
    })

    if (error) {
      console.error('OAuth error:', error.message)
    }
  }

  return (
    <button onClick={handleGoogleSignIn}>
      Sign in with Google
    </button>
  )
}

The redirectTo option specifies where Supabase sends the user after authentication. This must match one of the URLs you configured in Step 4.

Step 7: Handle the Auth Callback

After Google redirects back to your app via Supabase, you need to handle the session. Create a callback page at src/pages/AuthCallback.tsx:

import { useEffect } from 'react'
import { useNavigate } from 'react-router-dom'
import { supabase } from '../lib/supabase'

export function AuthCallback() {
  const navigate = useNavigate()

  useEffect(() => {
    supabase.auth.onAuthStateChange((event, session) => {
      if (event === 'SIGNED_IN' && session) {
        // User is signed in, redirect to your app
        navigate('/dashboard')
      }
    })
  }, [navigate])

  return <p>Completing sign in...</p>
}

Add this route in your App.tsx (assuming React Router):

import { Routes, Route } from 'react-router-dom'
import { AuthCallback } from './pages/AuthCallback'
import { Dashboard } from './pages/Dashboard'

function App() {
  return (
    <Routes>
      <Route path="/auth/callback" element={<AuthCallback />} />
      <Route path="/dashboard" element={<Dashboard />} />
    </Routes>
  )
}

Step 8: Read the User Session

To access the currently signed-in user throughout your app, use onAuthStateChange in a React context or hook.

Simple hook at src/hooks/useAuth.ts:

import { useState, useEffect } from 'react'
import { Session, User } from '@supabase/supabase-js'
import { supabase } from '../lib/supabase'

export function useAuth() {
  const [user, setUser] = useState<User | null>(null)
  const [session, setSession] = useState<Session | null>(null)
  const [loading, setLoading] = useState(true)

  useEffect(() => {
    // Get initial session
    supabase.auth.getSession().then(({ data: { session } }) => {
      setSession(session)
      setUser(session?.user ?? null)
      setLoading(false)
    })

    // Listen for auth state changes
    const { data: { subscription } } = supabase.auth.onAuthStateChange(
      (_event, session) => {
        setSession(session)
        setUser(session?.user ?? null)
      }
    )

    return () => subscription.unsubscribe()
  }, [])

  return { user, session, loading }
}

Use it in any component:

import { useAuth } from '../hooks/useAuth'

export function Dashboard() {
  const { user, loading } = useAuth()

  if (loading) return <p>Loading...</p>
  if (!user) return <p>Please sign in.</p>

  return (
    <div>
      <p>Welcome, {user.email}</p>
      <p>Name: {user.user_metadata.full_name}</p>
    </div>
  )
}

Step 9: Sign Out

const handleSignOut = async () => {
  const { error } = await supabase.auth.signOut()
  if (error) {
    console.error('Sign out error:', error.message)
  }
}

Call this function from a sign-out button. Supabase clears the session cookie and local storage automatically.

Troubleshooting

"redirect_uri_mismatch" error from Google The redirect URL Supabase is using does not match what you registered in Google Cloud Console. Go back to Step 2 and ensure https://your-project-ref.supabase.co/auth/v1/callback is listed under Authorised redirect URIs exactly as shown.

"Redirect URL not allowed" error from Supabase Your redirectTo URL is not listed in Supabase's allowed redirect URLs. Go to Authentication > URL Configuration and add the URL.

User lands on callback page but session is null The auth flow may have completed before your onAuthStateChange listener was registered. Add a getSession() call in the callback page useEffect as well as the onAuthStateChange listener (as shown in the useAuth hook above).

"This app isn't verified" warning on Google consent screen This appears for apps in testing mode with users who were not added as test users. Add the user's Google email to the Test users list in your Google Cloud OAuth consent screen, or publish the app after completing Google's verification process.

FAQ

Is the Supabase anon key safe to expose in the browser? Yes. The anon key is designed to be public. It grants only the permissions you configure via Row Level Security (RLS) policies in your database. Without appropriate RLS policies, it grants no write access by default.

Can I get the user's Google profile photo? Yes. After sign-in, user.user_metadata.avatar_url contains the URL of the user's Google profile picture.

Does Supabase store Google OAuth tokens? Supabase stores the user record in your auth.users table and manages session tokens. It does not store the Google access token or refresh token in your database by default.

How do I restrict which Google accounts can sign in? Use Supabase's Auth Hooks or a BEFORE_SIGN_IN hook to check the user's email domain and reject users who do not match your criteria. Alternatively, add an email allow-list in your Supabase dashboard under Authentication > Policies.

Can I add other OAuth providers alongside Google? Yes. Supabase supports GitHub, Apple, Twitter, Discord, Slack, and many others. Each provider follows the same pattern: create credentials in the provider's developer console and enter the client ID and secret in Supabase's provider settings.

With authentication in place, explore 1000+ free AI tools to add AI-powered features to your app, or follow the Vercel deployment guide to get your authenticated app live.