Login with Google OAuth using Expo, Clerk, and iOS — Finally Demystified
Source: Dev.to
Client ID + Client Secret: the introductory business card (and proof of identity)
Think of Google and Clerk like two companies.
- Client ID – your app’s “business card” (public identity).
- Client Secret – your app’s “sealed letter / private stamp” (private proof).
When you paste these from Google into Clerk, you’re basically saying:
“Clerk, when my app says ‘I’m the Google app you’re expecting’, here’s the official identity card and the private proof so you can trust it’s really me.”
Why it matters: without this formal introduction, Clerk can’t confidently talk to Google as your app, and Google won’t know which OAuth app configuration rules to apply.
Redirect URL must match: the relay race baton handoff
OAuth is a relay race:
- Your app sends the runner to Google (login screen).
- Google finishes its segment (user authenticates).
- Google must hand the baton back to the correct next runner.
That “handoff point” is the Redirect URL.
Rule: The redirect URL Google is allowed to hand the baton to must match what your app/Clerk expects.
That’s why you check both dashboards:
- Google Cloud Console: “These are the allowed handoff addresses.”
- Clerk: “This is the handoff address I’m expecting.”
If they don’t match, Google refuses the handoff (because it could be a security risk).
iOS must understand the redirect URL: Google → iOS → Your App
On mobile, the baton doesn’t go straight back into your app automatically. The flow is really:
Google → iOS (system) → Your App
So iOS needs to know:
“When I see a URL that looks like this, which installed app should receive it?”
That’s what these do:
app.jsonscheme – registers the “special address format” your app owns (like claiming a mailbox).- Expo Linking – helps your app listen for and parse the incoming redirect so it can resume the login flow.
In human terms: app.json tells iOS which app owns that URL, and Linking helps your app open the envelope and read what Google sent back.
Secure Store: where the baton gets locked up after the race
After OAuth succeeds, you end up with something sensitive stored on the phone (session tokens / refresh tokens, depending on the setup).
Key idea: A mobile app is not a safe place to keep secrets in plain storage. Tokens act like “proof you’re logged in.” If stolen, they can be reused like a copied keycard.
Solution: Use Secure Store as the phone’s built‑in safe:
- iOS Keychain / Android Keystore under the hood.
- Encrypted + protected by the OS.
Why it usually needs a rebuild: Secure Store is a native capability. If your project isn’t already including it in the native build (or you change native config), you need a new native build for it to be available properly.
In story form: once your app receives the baton (tokens), you don’t leave it on the table. You put it in the hotel safe (Secure Store), so nobody can copy it while you’re not looking.
One‑line summary
- Client ID/Secret = who you are (formal introduction)
- Redirect URL = where the baton goes (handoff point)
- Scheme/Linking = how iOS routes it (Google → iOS → app)
- Secure Store = where you lock the result (tokens in a safe)
Code to follow…
Next I will paste the React Native code here… please watch this space!