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:
| Type | Purpose | Where to register |
|---|---|---|
| Web | Server-side token exchange | Supabase Google Provider |
| Android | App signature verification | Google Cloud Console only |
| iOS | App bundle verification | Google Cloud Console only |
The key insight: Supabase only needs the Web Client. Android/iOS client IDs are never entered into Supabase.
Architecture
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
[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
- Google Cloud Console: Add Android/iOS client (package name + SHA-1 / Bundle ID)
- Flutter code: Copy the same Web Client ID
- Supabase: Connect to the same project URL + anon key
- 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:
keytool -list -v -keystore ~/.android/debug.keystore -alias androiddebugkey -storepass android
Summary
| Question | Answer |
|---|---|
| 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.