Langsung ke konten

Supabase Google Login - General Setup

This guide will walk you through integrating Google Sign-In with Supabase Authentication using the Capacitor Social Login plugin. This setup allows you to use native Google Sign-In on mobile platforms while leveraging Supabase Auth for backend authentication.

Before starting, ensure you have:

  1. Created a Supabase project

  2. Read the Google Login General Setup guide to setup Google OAuth credentials

  3. Followed the respective platform-specific guides to setup Google OAuth credentials for your target platform:

  1. Go to your Supabase Dashboard

  2. Click on your project

    Supabase Project Selector
  3. Do go to the Authentication menu

    Supabase Authentication Menu
  4. Click on the Providers tab

    Supabase Providers Tab
  5. Find the Google provider

    Supabase Google Provider
  6. Enable the provider

    Supabase Google Provider Enable
  7. Add the client IDs for the platforms you plan to use

    Supabase Google Provider Add Client IDs
  8. Click on the Save button

    Supabase Google Provider Save

Voilà, you have now enabled Google Sign-In with Supabase Authentication 🎉

How Google Sign-In with Supabase Authentication Helper Works

Section titled “How Google Sign-In with Supabase Authentication Helper Works”

This section explains how the Google Sign-In integration with Supabase works under the hood. Understanding this flow will help you implement and troubleshoot the authentication process.

The implementation generates a secure nonce pair following the Supabase nonce requirements:

// Generate URL-safe random nonce
function getUrlSafeNonce(): string {
const array = new Uint8Array(32);
crypto.getRandomValues(array);
return Array.from(array, (byte) => byte.toString(16).padStart(2, '0')).join('');
}
// Hash the nonce with SHA-256
async function sha256Hash(message: string): Promise<string> {
const encoder = new TextEncoder();
const data = encoder.encode(message);
const hashBuffer = await crypto.subtle.digest('SHA-256', data);
const hashArray = Array.from(new Uint8Array(hashBuffer));
return hashArray.map((b) => b.toString(16).padStart(2, '0')).join('');
}
// Generate nonce pair
async function getNonce(): Promise<{ rawNonce: string; nonceDigest: string }> {
const rawNonce = getUrlSafeNonce();
const nonceDigest = await sha256Hash(rawNonce);
return { rawNonce, nonceDigest };
}

Flow:

  • rawNonce: URL-safe random string (64 hex characters)
  • nonceDigest: SHA-256 hash of rawNonce (hex-encoded)
  • nonceDigest is passed to Google Sign-In → Google includes the nonce digest in the ID token
  • rawNonce is passed to Supabase → Supabase hashes the raw nonce and compares with the token’s nonce

The function initializes the plugin and signs in with Google:

await SocialLogin.initialize({
google: {
webClientId: 'YOUR_WEB_CLIENT_ID.apps.googleusercontent.com',
// iOS only:
iOSClientId: 'YOUR_IOS_CLIENT_ID.apps.googleusercontent.com',
mode: 'online', // Required to get idToken
},
});
const response = await SocialLogin.login({
provider: 'google',
options: {
scopes: ['email', 'profile'],
nonce: nonceDigest, // Pass the SHA-256 hashed nonce
},
});

Before sending the token to Supabase, the implementation validates the JWT token:

function validateJWTToken(idToken: string, expectedNonceDigest: string): { valid: boolean; error?: string } {
const decodedToken = decodeJWT(idToken);
// Check audience matches your Google Client IDs
const audience = decodedToken.aud;
if (!VALID_GOOGLE_CLIENT_IDS.includes(audience)) {
return { valid: false, error: 'Invalid audience' };
}
// Check nonce matches
const tokenNonce = decodedToken.nonce;
if (tokenNonce && tokenNonce !== expectedNonceDigest) {
return { valid: false, error: 'Nonce mismatch' };
}
return { valid: true };
}

Why validate before Supabase?

Validating the JWT token before sending the token to Supabase serves several important purposes:

  1. Prevent Invalid Requests: If the token has an incorrect audience or nonce mismatch, Supabase will reject the token anyway. Validating first avoids unnecessary API calls and provides clearer error messages.

  2. Token Caching Issues: On some platforms (especially iOS), Google Sign-In SDK can cache tokens for performance. When a cached token is returned, the cached token may have been generated with a different nonce (or no nonce at all), causing Supabase to reject the token with a “nonce mismatch” error. By validating before sending to Supabase, we can detect this issue early and automatically retry with a fresh token.

  3. Security (iOS): On iOS, validation ensures the token was issued for your specific Google Client IDs, preventing potential security issues from using tokens intended for other applications.

  4. Better Error Handling: Detecting issues before Supabase allows for automatic retry logic, which is essential for handling iOS caching issues transparently.

If validation fails, the function automatically:

  1. Logs out from Google (clears cached tokens - critical on iOS)
  2. Retries authentication once (forces fresh token generation with correct nonce)
  3. If retry also fails, returns an error

Finally, the validated token is sent to Supabase:

const { data, error } = await supabase.auth.signInWithIdToken({
provider: 'google',
token: googleResponse.idToken,
nonce: rawNonce, // Pass the raw (unhashed) nonce
});

The complete implementation is available in the example app’s supabaseAuthUtils.ts file, which includes:

  • getUrlSafeNonce() - Generates URL-safe random nonce
  • sha256Hash() - Hashes string with SHA-256
  • getNonce() - Generates nonce pair
  • decodeJWT() - Decodes JWT token
  • validateJWTToken() - Validates JWT audience and nonce
  • authenticateWithGoogleSupabase() - Main authentication function with automatic retry

Please proceed to the platform-specific setup guide for your target platform: