docs(auth-google): use onReady in Next.js one-tap component example (#37227)

* Update auth-google.mdx

* Update apps/docs/content/guides/auth/social-login/auth-google.mdx

* prettier fix
This commit is contained in:
Bayan Bennett authored and GitHub committed 2025-07-17 18:53:53 +00:00
1 parent e1cab2669d
commit 45e2d1b2d2
1 file changed
+57 -67
@@ -376,82 +376,72 @@ If you're integrating Google One-Tap with your Next.js application, you can refe
import Script from 'next/script'
import { createClient } from '@/utils/supabase/client'
import { CredentialResponse } from 'google-one-tap'
import type { accounts, CredentialResponse } from 'google-one-tap'
import { useRouter } from 'next/navigation'
import { useEffect } from 'react'
declare const google: { accounts: accounts }
// generate nonce to use for google id token sign-in
const generateNonce = async (): Promise<string[]> => {
const nonce = btoa(String.fromCharCode(...crypto.getRandomValues(new Uint8Array(32))))
const encoder = new TextEncoder()
const encodedNonce = encoder.encode(nonce)
const hashBuffer = await crypto.subtle.digest('SHA-256', encodedNonce)
const hashArray = Array.from(new Uint8Array(hashBuffer))
const hashedNonce = hashArray.map((b) => b.toString(16).padStart(2, '0')).join('')
return [nonce, hashedNonce]
}
const OneTapComponent = () => {
const supabase = createClient()
const router = useRouter()
// generate nonce to use for google id token sign-in
const generateNonce = async (): Promise<string[]> => {
const nonce = btoa(String.fromCharCode(...crypto.getRandomValues(new Uint8Array(32))))
const encoder = new TextEncoder()
const encodedNonce = encoder.encode(nonce)
const hashBuffer = await crypto.subtle.digest('SHA-256', encodedNonce)
const hashArray = Array.from(new Uint8Array(hashBuffer))
const hashedNonce = hashArray.map((b) => b.toString(16).padStart(2, '0')).join('')
const initializeGoogleOneTap = () => {
console.log('Initializing Google One Tap')
const [nonce, hashedNonce] = await generateNonce()
console.log('Nonce: ', nonce, hashedNonce)
return [nonce, hashedNonce]
// check if there's already an existing session before initializing the one-tap UI
const { data, error } = await supabase.auth.getSession()
if (error) {
console.error('Error getting session', error)
}
if (data.session) {
router.push('/')
return
}
/* global google */
google.accounts.id.initialize({
client_id: process.env.NEXT_PUBLIC_GOOGLE_CLIENT_ID,
callback: async (response: CredentialResponse) => {
try {
// send id token returned in response.credential to supabase
const { data, error } = await supabase.auth.signInWithIdToken({
provider: 'google',
token: response.credential,
nonce,
})
if (error) throw error
console.log('Session data: ', data)
console.log('Successfully logged in with Google One Tap')
// redirect to protected page
router.push('/')
} catch (error) {
console.error('Error logging in with Google One Tap', error)
}
},
nonce: hashedNonce,
// with chrome's removal of third-party cookies, we need to use FedCM instead (https://developers.google.com/identity/gsi/web/guides/fedcm-migration)
use_fedcm_for_prompt: true,
})
google.accounts.id.prompt() // Display the One Tap UI
}
useEffect(() => {
const initializeGoogleOneTap = () => {
console.log('Initializing Google One Tap')
window.addEventListener('load', async () => {
const [nonce, hashedNonce] = await generateNonce()
console.log('Nonce: ', nonce, hashedNonce)
// check if there's already an existing session before initializing the one-tap UI
const { data, error } = await supabase.auth.getSession()
if (error) {
console.error('Error getting session', error)
}
if (data.session) {
router.push('/')
return
}
/* global google */
google.accounts.id.initialize({
client_id: process.env.NEXT_PUBLIC_GOOGLE_CLIENT_ID,
callback: async (response: CredentialResponse) => {
try {
// send id token returned in response.credential to supabase
const { data, error } = await supabase.auth.signInWithIdToken({
provider: 'google',
token: response.credential,
nonce,
})
if (error) throw error
console.log('Session data: ', data)
console.log('Successfully logged in with Google One Tap')
// redirect to protected page
router.push('/')
} catch (error) {
console.error('Error logging in with Google One Tap', error)
}
},
nonce: hashedNonce,
// with chrome's removal of third-party cookies, we need to use FedCM instead (https://developers.google.com/identity/gsi/web/guides/fedcm-migration)
use_fedcm_for_prompt: true,
})
google.accounts.id.prompt() // Display the One Tap UI
})
}
initializeGoogleOneTap()
return () => window.removeEventListener('load', initializeGoogleOneTap)
}, [])
return (
<>
<Script src="https://accounts.google.com/gsi/client" />
<div id="oneTap" className="fixed top-0 right-0 z-[100]" />
</>
)
return <Script onReady={initializeGoogleOneTap} src="https://accounts.google.com/gsi/client" />
}
export default OneTapComponent