Back to Blog

Sharing One Google Sign-In Across Multiple Apps (Supabase + Flutter)

TL;DR

Register only the Web Client ID in Supabase. Android/iOS clients go in Google Cloud Console only. Supabase doesn't need to know about them. This works the same whether you have 1 app or 100.


The Problem

I'm building a platform called "Just Apps" — multiple apps (Just QR, Just Notes, etc.) sharing a single account system. Backend is Supabase, frontend is Flutter.

The question that tripped me up:

Supabase's Google Provider only accepts one Client ID. How do I support multiple apps?

This led me down a rabbit hole of trying signInWithOAuth (browser-based flow), which turned out to be a dead end for mobile multi-app setups. Custom URL schemes aren't accepted in Redirect URLs, and Site URL only supports one value.

The answer was much simpler: the original google_sign_in + signInWithIdToken approach was correct all along.


Understanding Google OAuth Client Types

When you create OAuth clients in Google Cloud Console, there are distinct types:

TypePurposeWhere to register
WebServer-side token exchangeSupabase Google Provider
AndroidApp signature verificationGoogle Cloud Console only
iOSApp bundle verificationGoogle Cloud Console only

The key insight: Supabase only needs the Web Client. Android/iOS client IDs are never entered into Supabase.


Architecture

TEXT
Google Cloud Project (Just Apps)
├── Web Client (1)
│   └── Registered in Supabase Google Provider
│   └── Used as serverClientId in all Flutter apps
├── Android Client - Just QR debug
│   └── Package: com.justkihyun.justqr + debug SHA-1
├── Android Client - Just QR release
│   └── Package: com.justkihyun.justqr + release SHA-1
├── Android Client - Just Notes debug
│   └── Package: com.justkihyun.justnotes + debug SHA-1
├── Android Client - Just Notes release
│   └── Package: com.justkihyun.justnotes + release SHA-1
├── iOS Client - Just QR
│   └── Bundle ID: com.justkihyun.justqr
└── iOS Client - Just Notes
    └── Bundle ID: com.justkihyun.justnotes

The Flow

TEXT
[Flutter App]
    ├── google_sign_in package → native Google login UI
    │   (Google SDK auto-matches Android Client by package name + SHA-1)
    ├── Receives idToken + accessToken
    └── Calls Supabase signInWithIdToken()
        (Supabase validates token using Web Client ID + Secret)
        └── Same Supabase project → same auth.users → same account

Different apps + same Google account = same Supabase user. Because the Web Client ID is the same.


Adding a New App

  1. Google Cloud Console: Add Android/iOS client (package name + SHA-1 / Bundle ID)
  2. Flutter code: Copy the same Web Client ID
  3. Supabase: Connect to the same project URL + anon key
  4. Done

Zero changes needed in Supabase settings.


Why signInWithOAuth Doesn't Work for This

I tried the browser-based OAuth approach. Here's why it failed:

  • Supabase Site URL only accepts one value → only one app can receive callbacks
  • Redirect URLs reject custom schemes (myapp://) — only http/https allowed
  • PKCE flow doesn't solve this fundamental limitation

For native mobile apps in a multi-app setup, google_sign_in + signInWithIdToken is the only viable path.


Common Misconceptions

"Don't I need to register a Client ID per app in Supabase?"

No. Supabase only knows about the Web Client. Android/iOS clients live exclusively in Google Cloud Console. They're used by the Google SDK for app signature verification, not by Supabase.

"I'm getting ApiException: 10"

Your debug SHA-1 fingerprint isn't registered in Google Cloud Console. Get it with keytool and add an Android client:

Bash
keytool -list -v -keystore ~/.android/debug.keystore -alias androiddebugkey -storepass android

Summary

QuestionAnswer
What goes in Supabase?1 Web Client ID
Per-app setup?Add Android/iOS client in Google Cloud Console
Supabase config changes?None
Account sharing?Automatic if same Supabase project
Terms agreement sharing?Share a user_agreements table

Don't overthink it. Use Google's OAuth the way it was designed.

Comments