「Google でログイン」をタップした瞬間、画面いっぱいに エラー 400: redirect_uri_mismatch が出る — Rork で OAuth を実装した方なら、一度は見たことがある赤い画面ではないでしょうか。私自身、累計 5,000 万 DL のアプリ事業を運営する中で、新規プロジェクトに Google サインインを入れるたびに 30 分から 1 時間ほどこのエラーと格闘してきました。
特に Rork で生成されたコードは、Expo の Managed Workflow を前提にしているため、ネイティブの URL Schemes や Android の SHA-1 証明書まわりの設定がブラックボックスになりがちです。AI に「直して」と頼んでもコードだけが書き換わり、Google Cloud Console 側の設定とずれたままになると、何度ビルドし直しても同じエラーが再発します。
Rork で Google サインインを実装したときに redirect_uri_mismatch が出る原因を 5 つのチェックポイントに整理し、確認順序とコマンドつきで素早く解決する手順を順番にご紹介します。
なぜ Rork で redirect_uri_mismatch が起きやすいのか
Google サインインの裏側では、ブラウザ(または In-App Browser)が認証画面を開き、認証完了後にあらかじめ登録された URI へリダイレクトしてアプリに戻ります。Google は、このリダイレクト先 URI が Google Cloud Console に登録した値と完全一致しているかを厳密にチェックします。1 文字でも違うと redirect_uri_mismatch が返されます。
Rork で生成されたアプリでは、expo-auth-session ライブラリがリダイレクト URI を自動生成します。問題は、この自動生成 URI が以下のように環境ごとに変わる点です。
- Expo Go(プレビュー)で起動:
https://auth.expo.io/@your-username/your-slug - EAS Build(開発ビルド):
your.bundle.id:// - 本番ビルド(iOS):
your.bundle.id://oauthredirect - 本番ビルド(Android):
your.bundle.id:/oauth2redirect/google(コロン1つに注意)
つまり「プレビューでは動いていたのに、TestFlight に上げたら動かない」というのは、Google Cloud Console にプレビュー用の URI しか登録していないことが原因です。私も最初にハマったとき、ここに気づくのに数時間かかりました。
チェック1: Google Cloud Console の OAuth クライアントを3種類すべて作る
意外と見落とされがちですが、Google サインインを完全動作させるには OAuth クライアントを 3 種類作成する必要があります。
- iOS 用クライアント(アプリケーションの種類: iOS)
- Android 用クライアント(アプリケーションの種類: Android)
- ウェブ用クライアント(アプリケーションの種類: ウェブアプリケーション)
「ウェブ用クライアントは要らないでしょ」と思いがちですが、expo-auth-session の Google.useAuthRequest は内部的にウェブ用クライアント ID を必要とします。これがないと、Expo Go プレビューで動かなかったり、iOS でも特定のフローで失敗したりします。
ウェブ用クライアントの「承認済みのリダイレクト URI」には、最低限以下の 2 つを登録しておきます。
https://auth.expo.io/@your-expo-username/your-app-slug
https://your.bundle.id/oauth2redirect
your-expo-username と your-app-slug は、app.json の owner フィールドと slug フィールドの値を入れます。Rork で作成したプロジェクトは slug が自動生成されているので、必ず app.json を開いて確認してから登録してください。
チェック2: Bundle ID と Package Name の完全一致
iOS クライアントの「Bundle ID」と Android クライアントの「パッケージ名」は、app.json(または app.config.js)と大文字・小文字・ピリオドまで完全一致させる必要があります。
// app.json
{
"expo": {
"ios": {
"bundleIdentifier": "com.yourname.rorkapp"
},
"android": {
"package": "com.yourname.rorkapp"
}
}
}Rork で生成されたコードに com.example.app のようなプレースホルダーが残っていないかも確認してください。私が以前担当したプロジェクトでは、app.json だけ書き換えて eas.json の prebuild 設定で別の Bundle ID が混入し、本番ビルドだけが認証エラーになる事故が発生しました。
確認用のワンライナーは以下の通りです。
# Bundle ID と Package Name が一致しているか確認
grep -E "bundleIdentifier|package" app.json
grep -rE "bundleIdentifier|applicationId|packageName" eas.json android/ ios/ 2>/dev/nullチェック3: Android の SHA-1 証明書フィンガープリントを正しく登録する
Android で redirect_uri_mismatch が消えない最大の原因は SHA-1 証明書フィンガープリントの登録漏れ・誤りです。Android では、署名証明書ごとに別アプリと見なされるため、debug ビルドと release ビルドで別の SHA-1 を登録する必要があります。
EAS Build を使っている場合、SHA-1 は次のコマンドで確認できます。
# プロジェクトルートで実行
eas credentials -p androidメニューから「Keystore: Manage everything needed to build your project」→「Show keystore credentials」を選ぶと、SHA-1 と SHA-256 が表示されます。これを Google Cloud Console の Android クライアントに登録してください。
期待する出力例:
SHA1 Fingerprint: A1:B2:C3:D4:E5:F6:...
SHA256 Fingerprint: A1:B2:C3:D4:E5:F6:...
注意点として、eas build --profile preview で作った内部配布版と eas build --profile production の本番版は別の Keystore を使うことが多いです。プロファイルごとに SHA-1 を確認し、必要な分だけ Android クライアントに登録してください。
私が個人開発で運営しているアプリでは、eas.json を以下のように整えて、プロファイルごとの Keystore を明示的に管理しています。
{
"build": {
"preview": {
"distribution": "internal",
"android": { "buildType": "apk" }
},
"production": {
"android": { "buildType": "app-bundle" }
}
}
}チェック4: Expo の scheme と iOS の URL Schemes の整合性
iOS では、認証完了後にカスタム URL スキームでアプリへ戻ります。app.json の scheme と Info.plist の CFBundleURLSchemes、そして Google Cloud Console の iOS クライアントが提供する逆引き Bundle ID が一致している必要があります。
逆引き Bundle ID は、Google Cloud Console の iOS クライアント詳細画面に表示される値で、以下の形式です。
com.googleusercontent.apps.123456789012-abcdefghijklmnop
これを app.json に登録します。
{
"expo": {
"scheme": "rorkapp",
"ios": {
"infoPlist": {
"CFBundleURLTypes": [
{
"CFBundleURLSchemes": [
"com.googleusercontent.apps.123456789012-abcdefghijklmnop"
]
}
]
}
}
}
}scheme と CFBundleURLSchemes を両方設定するのがポイントです。Rork が生成したコードに scheme だけがあって CFBundleURLSchemes が無い場合、iOS 上で認証が成功してもアプリへ戻れず、Safari に取り残されます。
app.json を変更したあとは必ず npx expo prebuild --clean で ios/ を再生成し、eas build し直してください。プレビューでは動いても、ネイティブビルドではこの設定が効くため、ローカル設定の差で挙動が変わります。
チェック5: 動作確認用のミニマル実装で原因を切り分ける
ここまで設定をひとつずつ確認しても直らない場合、expo-auth-session の最小実装に戻して切り分けるのが一番早い方法です。私は、原因が見えなくなったら必ずこのパターンに戻して挙動を確認しています。
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>
);
}期待する出力:画面に表示される redirectUri の値が、Google Cloud Console に登録したリダイレクト URI と完全一致していることです。
ここで表示される URI をコピペで Google Cloud Console の「承認済みのリダイレクト URI」に貼り付ければ、redirect_uri_mismatch は確実に消えます。私は最初の頃、目視で確認していてピリオドの数を間違えていたことがあるので、必ずコピペで照合する習慣をつけることをお勧めします。
Rork でやり直す時のプロンプト例
ここまで確認しても解消しない場合は、Rork に以下のように指示すると一発で整います。
expo-auth-session の Google プロバイダを使った Google サインインを実装してください。
以下を必ず守ってください:
1. iosClientId と androidClientId と webClientId を環境変数から読み込む
2. app.json の scheme を 'rorkapp' に設定する
3. iOS の CFBundleURLSchemes に逆引き Bundle ID を追加する
4. ログイン画面に request.redirectUri を表示するデバッグ用 Text を入れる
5. response.type === 'error' のときに Alert で詳細を表示する
特に 4 番目の「redirectUri を画面に表示する」を仕込んでおくと、本番でエラーが出てもユーザーから URI 文字列をスクリーンショットで送ってもらえるので、原因の切り分けが一気に楽になります。
全体を振り返ってと次のステップ
redirect_uri_mismatch は、Google Cloud Console と Expo 側の設定がほんのわずかにズレているだけで発生します。今回の 5 つのチェックポイントを順番に通すと、ほぼすべてのケースで原因にたどり着けるはずです。
次にやるべきことは、いま開発中のプロジェクトで「Expo Go」「EAS preview」「EAS production」の 3 ビルドそれぞれで Google サインインが通ることを手元で確認しておくことです。本番リリース直前にここで詰まると、リリースが 1 〜 2 日遅れることがあります。普段からこの 3 ビルドを定期的に試す癖をつけておくと、後から大きな手戻りを防げます。
なお、認証まわりをより堅牢に作りたい方には Firebase / Supabase 認証エラーの解決ガイド や Clerk のソーシャルログイン実装ガイド も参考になります。Clerk を使うと、ここまで紹介した OAuth クライアント設定の多くがダッシュボード経由で完結するため、個人開発の効率が大きく上がります。
実装の参考になれば幸いです。同じ場所で詰まっている方の助けになれば嬉しく思います。