RORK LABJP
TOOLING — Rork's developer repos keep moving: rork-xcode was updated on July 16, rork-device on July 15, and rork-plist on July 13OPUS46 — Claude Opus 4.6 is live in Rork, and Rork Max is built to assemble apps on top of Claude CodeSIM — A cloud iOS simulator runs in the browser, with one click to install on a device and two clicks to publish to the App StoreMAX — Rork Max emits pure Swift rather than React Native, reaching iPhone, iPad, Apple Watch, Apple TV, Vision Pro, and even iMessageNATIVE — That opens up HealthKit, ARKit and LiDAR, NFC, Dynamic Island, Live Activities, 3D through Metal, and on-device inference with Core MLSEED — Rork raised a $15M seed led by Left Lane Capital, with Peak XV and a16z Speedrun joining the roundTOOLING — Rork's developer repos keep moving: rork-xcode was updated on July 16, rork-device on July 15, and rork-plist on July 13OPUS46 — Claude Opus 4.6 is live in Rork, and Rork Max is built to assemble apps on top of Claude CodeSIM — A cloud iOS simulator runs in the browser, with one click to install on a device and two clicks to publish to the App StoreMAX — Rork Max emits pure Swift rather than React Native, reaching iPhone, iPad, Apple Watch, Apple TV, Vision Pro, and even iMessageNATIVE — That opens up HealthKit, ARKit and LiDAR, NFC, Dynamic Island, Live Activities, 3D through Metal, and on-device inference with Core MLSEED — Rork raised a $15M seed led by Left Lane Capital, with Peak XV and a16z Speedrun joining the round
Articles/Dev Tools
Dev Tools/2026-05-09Intermediate

5 Things to Check When Google Sign-In Throws redirect_uri_mismatch in Your Rork App

When your Rork app keeps throwing redirect_uri_mismatch on Google Sign-In, the gap is almost always between Google Cloud Console and your Expo config. Here are 5 checks that resolve it for good.

troubleshooting65Google Sign-InOAuth2authentication4expo-auth-sessionRork515

The moment a tester taps "Sign in with Google" and the screen explodes into Error 400: redirect_uri_mismatch — if you have wired OAuth into a Rork app, you have probably seen that red screen at least once. After running an indie app business with over 50 million cumulative downloads, I still spend 30 to 60 minutes per project lining up Google Sign-In whenever I add it to a fresh codebase.

Rork-generated apps make this trickier than usual because they assume the Expo Managed Workflow, which hides native URL Schemes and the Android SHA-1 certificate dance behind generated config. Asking the AI to "just fix it" only updates code; if Google Cloud Console stays out of sync, you can rebuild forever and still get the same red screen.

This guide walks through 5 checkpoints that pinpoint why redirect_uri_mismatch appears in a Rork project, with the exact commands and config snippets to use along the way.

Why redirect_uri_mismatch is so common in Rork projects

Behind the scenes, Google opens a browser (or in-app browser) for the user, and on success redirects back to a URI that you registered ahead of time. Google then verifies that the redirect URI matches exactly what is stored in the OAuth client. A single character off and you get redirect_uri_mismatch.

In Rork apps, the redirect URI is auto-generated by expo-auth-session. The trap is that this URI changes per environment:

  • Expo Go (preview): https://auth.expo.io/@your-username/your-slug
  • EAS development build: your.bundle.id://
  • iOS production build: your.bundle.id://oauthredirect
  • Android production build: your.bundle.id:/oauth2redirect/google (note the single colon)

That is why "it worked in preview but TestFlight breaks" happens so often. You probably only registered the preview URI in Google Cloud Console. I lost half a day to this on my first project before noticing the pattern.

Check 1: Create all three OAuth clients in Google Cloud Console

A frequently missed detail: a fully working Google Sign-In flow needs three OAuth clients, not one or two.

  • iOS client (application type: iOS)
  • Android client (application type: Android)
  • Web client (application type: Web application)

It feels like the Web client should be optional in a mobile-only project, but expo-auth-session's Google.useAuthRequest internally needs the Web client ID. Without it, Expo Go preview fails outright and certain iOS flows silently break.

Under your Web client, add at least these two entries to "Authorized redirect URIs":

https://auth.expo.io/@your-expo-username/your-app-slug
https://your.bundle.id/oauth2redirect

Replace your-expo-username and your-app-slug with the actual values from your app.json (owner and slug fields). Rork generates a slug automatically, so always open app.json and copy from there rather than typing from memory.

Check 2: Match Bundle ID and Package Name exactly

The "Bundle ID" in the iOS client and the "Package name" in the Android client must match app.json (or app.config.js) exactly — including case and dot placement.

// app.json
{
  "expo": {
    "ios": {
      "bundleIdentifier": "com.yourname.rorkapp"
    },
    "android": {
      "package": "com.yourname.rorkapp"
    }
  }
}

Also check that placeholders like com.example.app did not leak through from Rork's scaffolding. On a project I once inherited, only app.json had been updated; an older Bundle ID lingered in eas.json's prebuild config, so the production build alone failed authentication.

Quick verification one-liners:

# Confirm Bundle ID and Package Name match
grep -E "bundleIdentifier|package" app.json
grep -rE "bundleIdentifier|applicationId|packageName" eas.json android/ ios/ 2>/dev/null

Check 3: Register the right SHA-1 certificate fingerprints for Android

The single biggest cause of stubborn redirect_uri_mismatch errors on Android is missing or wrong SHA-1 fingerprints. Android treats apps signed with different certificates as different apps, so debug builds and release builds need separate SHA-1 entries.

When using EAS Build, fetch your SHA-1 with:

# From the project root
eas credentials -p android

Choose "Keystore: Manage everything needed to build your project" → "Show keystore credentials". The CLI prints both SHA-1 and SHA-256, which you then paste into the Android client in Google Cloud Console.

Expected output:

SHA1 Fingerprint: A1:B2:C3:D4:E5:F6:...
SHA256 Fingerprint: A1:B2:C3:D4:E5:F6:...

A subtle gotcha: eas build --profile preview (internal distribution) often uses a different keystore from eas build --profile production. Check the SHA-1 for each profile you actually ship and add them all to the Android client.

For my own indie apps I keep eas.json explicit so each profile maps cleanly to its keystore:

{
  "build": {
    "preview": {
      "distribution": "internal",
      "android": { "buildType": "apk" }
    },
    "production": {
      "android": { "buildType": "app-bundle" }
    }
  }
}

Check 4: Align Expo's scheme with iOS URL Schemes

On iOS, the system returns to your app via a custom URL scheme after authentication. Three things must agree: scheme in app.json, CFBundleURLSchemes in Info.plist, and the reversed Bundle ID Google Cloud Console gives you on the iOS client.

The reversed Bundle ID looks like this in the iOS client detail view:

com.googleusercontent.apps.123456789012-abcdefghijklmnop

Add it to app.json as follows:

{
  "expo": {
    "scheme": "rorkapp",
    "ios": {
      "infoPlist": {
        "CFBundleURLTypes": [
          {
            "CFBundleURLSchemes": [
              "com.googleusercontent.apps.123456789012-abcdefghijklmnop"
            ]
          }
        ]
      }
    }
  }
}

Setting both scheme and CFBundleURLSchemes is the key. If Rork-generated code only declares scheme, iOS will succeed at the auth screen but fail to return to your app — leaving the user stranded in Safari.

After editing app.json, always run npx expo prebuild --clean to regenerate ios/, then rebuild with eas build. Preview may still appear to work, because this setting only takes effect on native builds.

Check 5: Isolate the cause with a minimal repro

If careful auditing of the four checkpoints above still does not fix it, fall back to a minimal expo-auth-session implementation. Whenever I get stuck and lose track of which knob is wrong, I always return to this pattern.

import * as Google from 'expo-auth-session/providers/google';
import * as WebBrowser from 'expo-web-browser';
import { useEffect } from 'react';
import { Button, Text, View, Alert } from 'react-native';
 
WebBrowser.maybeCompleteAuthSession();
 
export default function GoogleLoginDebug() {
  const [request, response, promptAsync] = Google.useAuthRequest({
    iosClientId: 'YOUR_IOS_CLIENT_ID.apps.googleusercontent.com',
    androidClientId: 'YOUR_ANDROID_CLIENT_ID.apps.googleusercontent.com',
    webClientId: 'YOUR_WEB_CLIENT_ID.apps.googleusercontent.com',
  });
 
  useEffect(() => {
    if (response?.type === 'success') {
      const { authentication } = response;
      Alert.alert('Success', 'Token: ' + authentication?.accessToken?.slice(0, 20));
    } else if (response?.type === 'error') {
      Alert.alert('Error', JSON.stringify(response.error));
    }
  }, [response]);
 
  return (
    <View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
      <Text>Redirect URI debug</Text>
      <Text selectable>{request?.redirectUri}</Text>
      <Button
        disabled={!request}
        title="Login with Google"
        onPress={() => promptAsync()}
      />
    </View>
  );
}

Expected behavior: the redirectUri printed on screen exactly matches the redirect URI you have registered in Google Cloud Console.

Copy that displayed URI character-for-character into Google Cloud Console's "Authorized redirect URIs" list and redirect_uri_mismatch disappears for good. I used to eyeball this in the early days and once miscounted dots — copy/paste rather than retyping is a discipline worth keeping.

A reusable Rork prompt to set this up correctly

When the issue refuses to budge, I lean on Rork with a tightly scoped prompt that covers every checkpoint above:

Implement Google Sign-In using the Google provider in expo-auth-session.
Please follow these constraints exactly:

1. Read iosClientId, androidClientId, and webClientId from environment variables.
2. Set the scheme in app.json to 'rorkapp'.
3. Add the reversed Bundle ID to CFBundleURLSchemes on iOS.
4. Show request.redirectUri on the login screen as a debug Text element.
5. When response.type === 'error', surface the details via an Alert.

Item 4 is especially worth keeping in production. If a tester or end-user hits an error, they can screenshot the redirectUri string and send it to you directly — turning a vague "Google Sign-In does not work" report into a one-line diff against your registered URIs.

Wrapping up and next steps

redirect_uri_mismatch happens because the smallest possible gap exists between Google Cloud Console and your Expo configuration. Walking through the five checks in order resolves nearly every case.

The next concrete action: on your current project, verify Google Sign-In end-to-end on all three builds — Expo Go, EAS preview, and EAS production. Discovering a misalignment the night before submission can delay a release by a day or two. Making this a routine habit pays off the day you actually need to ship in a hurry.

If you want to make the rest of your auth stack more resilient, Firebase / Supabase auth error fix guide and Clerk social login implementation guide are good companions. Clerk in particular handles much of the OAuth client wiring through its dashboard, which can save a lot of indie-developer time.

I hope this saves you the hours I spent on it the first time. Wishing you a clean redirect on your next build.

Share

Thank You for Reading

Rork Lab is ad-free, supported entirely by members like you. We publish practical guides daily with implementation code, benchmarks, and production-ready patterns. If you've found it useful, we'd love to have you on board.

  • Copy-paste ready implementation code
  • New advanced guides published daily
  • $5/mo or $10 for lifetime access
View Membership →

If you found this article helpful, a small tip ($1.50) would mean a lot to us. Your support helps keep this site ad-free and covers server and hosting costs.

Related Articles

Dev Tools2026-06-21
Where Should Your Rork App Store Auth Tokens? expo-secure-store and a Biometric Gate
How I moved a Rork-generated app's auth tokens out of AsyncStorage into expo-secure-store and put a biometric check in front of every read — including the size limit and sign-out gotchas I hit in production.
Dev Tools2026-06-12
Your Rork App's 'Documents & Data' Keeps Growing — Taming expo-image's Disk Cache
My wallpaper app's binary was 40 MB, yet 'Documents & Data' had ballooned to 2.4 GB. Here is how I diagnosed expo-image's unbounded disk cache and fixed it with cachePolicy tuning, thumbnail URLs, and generational cache clearing.
Dev Tools2026-05-26
iOS Foreground Notifications Disappear in Expo — A Practical Fix Guide
A focused walkthrough of why iOS silently drops push notifications when the app is in the foreground, and how to wire setNotificationHandler correctly for iOS 14+ with expo-notifications.
📚RECOMMENDED BOOKS
Build a Large Language Model (From Scratch)
Sebastian Raschka
LLM Dev
Prompt Engineering for LLMs
Berryman & Ziegler
Prompting
AI Engineering
Chip Huyen
AI Eng
* Contains affiliate links
See all →