Login with Google
Supabase Auth supports Sign in with Google for the web, native Android applications, and Chrome extensions.
Prerequisites
- A Google Cloud project. Go to the Google Cloud Platform and create a new project if necessary.
Configuration
To support Sign In with Google, you need to configure the Google provider for your Supabase project.
For web applications, you can set up your signin button two different ways:
- Use your own application code for the button.
- Use Google's pre-built sign-in or OneTap flows.
Application code configuration
To use your own application code:
-
In the Google Cloud console, go to the Consent Screen configuration page. The consent screen is the view shown to your users when they consent to signing in to your app.
-
Under Authorized domains, add your Supabase project's domain, which has the form
<PROJECT_ID>.supabase.co
. -
Configure the following non-sensitive scopes:
.../auth/userinfo.email
...auth/userinfo.profile
openid
-
Go to the API Credentials page.
-
Click
Create credentials
and chooseOAuth Client ID
. -
For application type, choose
Web application
. -
Under Authorized JavaScript origins, add your site URL.
-
Under Authorized redirect URLs, enter the callback URL from the Supabase dashboard. Expand the Google Auth Provider section to display it.
The redirect URL is visible to your users. You can customize it by configuring custom domains.
-
When you finish configuring your credentials, you will be shown your client ID and secret. Add these to the Google Auth Provider section of the Supabase Dashboard.
In local development, you can add the client ID and secret to your
config.toml
file.
Google pre-built configuration
To use Google's pre-built signin buttons:
- In the Google Cloud console, go to the Consent Screen configuration page. The consent screen is the view shown to your users when they consent to signing in to your app.
- Configure the screen to your liking, making sure you add links to your app's privacy policy and terms of service.
- Go to the API Credentials page.
- Click
Create credentials
and chooseOAuth Client ID
. - For application type, choose
Web application
. - Under Authorized JavaScript origins and Authorized redirect URLs, add your site URL. This is the URL of the website where the signin button will appear, not your Supabase project domain. If you're testing in localhost, ensure that you have
http://localhost
set in the Authorized JavaScript origins section as well. This is important when integrating with Google One-Tap to ensure you can use it locally. - When you finish configuring your credentials, you will be shown your client ID. Add this to the Client IDs field in the Google Auth Provider section of the Supabase Dashboard. Leave the OAuth client ID and secret blank. You don't need them when using Google's pre-built approach.
Signing users in
Application code
To use your own application code for the signin button, call the signInWithOAuth
method (or the equivalent for your language).
Make sure you're using the right supabase
client in the following code.
If you're not using Server-Side Rendering or cookie-based Auth, you can directly use the createClient
from @supabase/supabase-js
. If you're using Server-Side Rendering, see the Server-Side Auth guide for instructions on creating your Supabase client.
_10supabase.auth.signInWithOAuth({_10 provider: 'google',_10})
For an implicit flow, that's all you need to do. The user will be taken to Google's consent screen, and finally redirected to your app with an access and refresh token pair representing their session.
For a PKCE flow, for example in Server-Side Auth, you need an extra step to handle the code exchange. When calling signInWithOAuth
, provide a redirectTo
URL which points to a callback route. This redirect URL should be added to your redirect allow list.
In the browser, signInWithOAuth
automatically redirects to the OAuth provider's authentication endpoint, which then redirects to your endpoint.
_10await supabase.auth.signInWithOAuth({_10 provider,_10 options: {_10 redirectTo: `http://example.com/auth/callback`,_10 },_10})
At the callback endpoint, handle the code exchange to save the user session.
Create a new file at app/auth/callback/route.ts
and populate with the following:
After a successful code exchange, the user's session will be saved to cookies.
Saving Google tokens
The tokens saved by your application are the Supabase Auth tokens. Your app might additionally need the Google OAuth 2.0 tokens to access Google services on the user's behalf.
On initial login, you can extract the provider_token
from the session and store it in a secure storage medium. The session is available in the returned data from signInWithOAuth
(implicit flow) and exchangeCodeForSession
(PKCE flow).
Google does not send out a refresh token by default, so you will need to pass parameters like these to signInWithOAuth()
in order to extract the provider_refresh_token
:
_10const { data, error } = await supabase.auth.signInWithOAuth({_10 provider: 'google',_10 options: {_10 queryParams: {_10 access_type: 'offline',_10 prompt: 'consent',_10 },_10 },_10})
Google pre-built
Most web apps and websites can utilize Google's personalized sign-in buttons, One Tap or automatic sign-in for the best user experience.
-
Load the Google client library in your app by including the third-party script:
_10<script src="https://accounts.google.com/gsi/client" async></script> -
Use the HTML Code Generator to customize the look, feel, features and behavior of the Sign in with Google button.
-
Pick the Swap to JavaScript callback option, and input the name of your callback function. This function will receive a
CredentialResponse
when sign in completes.To make your app compatible with Chrome's third-party-cookie phase-out, make sure to set
data-use_fedcm_for_prompt
totrue
.Your final HTML code might look something like this:
_21<div_21id="g_id_onload"_21data-client_id="<client ID>"_21data-context="signin"_21data-ux_mode="popup"_21data-callback="handleSignInWithGoogle"_21data-nonce=""_21data-auto_select="true"_21data-itp_support="true"_21data-use_fedcm_for_prompt="true"_21></div>_21_21<div_21class="g_id_signin"_21data-type="standard"_21data-shape="pill"_21data-theme="outline"_21data-text="signin_with"_21data-size="large"_21data-logo_alignment="left"_21></div> -
Create a
handleSignInWithGoogle
function that takes theCredentialResponse
and passes the included token to Supabase. The function needs to be available in the global scope for Google's code to find it._10async function handleSignInWithGoogle(response) {_10const { data, error } = await supabase.auth.signInWithIdToken({_10provider: 'google',_10token: response.credential,_10})_10} -
(Optional) Configure a nonce. The use of a nonce is recommended for extra security, but optional. The nonce should be generated randomly each time, and it must be provided in both the
data-nonce
attribute of the HTML code and the options of the callback function._10async function handleSignInWithGoogle(response) {_10const { data, error } = await supabase.auth.signInWithIdToken({_10provider: 'google',_10token: response.credential,_10nonce: '<NONCE>',_10})_10}Note that the nonce should be the same in both places, but because Supabase Auth expects the provider to hash it (SHA-256, hexadecimal representation), you need to provide a hashed version to Google and a non-hashed version to
signInWithIdToken
.You can get both versions by using the in-built
crypto
library:_12// Adapted from https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto/digest#converting_a_digest_to_a_hex_string_12_12const nonce = btoa(String.fromCharCode(...crypto.getRandomValues(new Uint8Array(32))))_12const encoder = new TextEncoder()_12const encodedNonce = encoder.encode(nonce)_12crypto.subtle.digest('SHA-256', encodedNonce).then((hashBuffer) => {_12const hashArray = Array.from(new Uint8Array(hashBuffer))_12const hashedNonce = hashArray.map((b) => b.toString(16).padStart(2, '0')).join('')_12})_12_12// Use 'hashedNonce' when making the authentication request to Google_12// Use 'nonce' when invoking the supabase.auth.signInWithIdToken() method
One-tap with Next.js
If you're integrating Google One-Tap with your Next.js application, you can refer to the example below to get started:
_83'use client'_83_83import Script from 'next/script'_83import { createClient } from '@/utils/supabase/client'_83import { CredentialResponse } from 'google-one-tap'_83import { useRouter } from 'next/navigation'_83import { useEffect } from 'react'_83_83const OneTapComponent = () => {_83 const supabase = createClient()_83 const router = useRouter()_83_83 // generate nonce to use for google id token sign-in_83 const generateNonce = async (): Promise<string[]> => {_83 const nonce = btoa(String.fromCharCode(...crypto.getRandomValues(new Uint8Array(32))))_83 const encoder = new TextEncoder()_83 const encodedNonce = encoder.encode(nonce)_83 const hashBuffer = await crypto.subtle.digest('SHA-256', encodedNonce)_83 const hashArray = Array.from(new Uint8Array(hashBuffer))_83 const hashedNonce = hashArray.map((b) => b.toString(16).padStart(2, '0')).join('')_83_83 return [nonce, hashedNonce]_83 }_83_83 useEffect(() => {_83 const initializeGoogleOneTap = () => {_83 console.log('Initializing Google One Tap')_83 window.addEventListener('load', async () => {_83 const [nonce, hashedNonce] = await generateNonce()_83 console.log('Nonce: ', nonce, hashedNonce)_83_83 // check if there's already an existing session before initializing the one-tap UI_83 const { data, error } = await supabase.auth.getSession()_83 if (error) {_83 console.error('Error getting session', error)_83 }_83 if (data.session) {_83 router.push('/')_83 return_83 }_83_83 /* global google */_83 google.accounts.id.initialize({_83 client_id: process.env.NEXT_PUBLIC_GOOGLE_CLIENT_ID,_83 callback: async (response: CredentialResponse) => {_83 try {_83 // send id token returned in response.credential to supabase_83 const { data, error } = await supabase.auth.signInWithIdToken({_83 provider: 'google',_83 token: response.credential,_83 nonce,_83 })_83_83 if (error) throw error_83 console.log('Session data: ', data)_83 console.log('Successfully logged in with Google One Tap')_83_83 // redirect to protected page_83 router.push('/')_83 } catch (error) {_83 console.error('Error logging in with Google One Tap', error)_83 }_83 },_83 nonce: hashedNonce,_83 // with chrome's removal of third-party cookiesm, we need to use FedCM instead (https://developers.google.com/identity/gsi/web/guides/fedcm-migration)_83 use_fedcm_for_prompt: true,_83 })_83 google.accounts.id.prompt() // Display the One Tap UI_83 })_83 }_83 initializeGoogleOneTap()_83 return () => window.removeEventListener('load', initializeGoogleOneTap)_83 }, [])_83_83 return (_83 <>_83 <Script src="https://accounts.google.com/gsi/client" />_83 <div id="oneTap" className="fixed top-0 right-0 z-[100]" />_83 </>_83 )_83}_83_83export default OneTapComponent