RORK LABEN
TOOLING — Rorkの開発者向けリポジトリが動き続けています。rork-xcodeが7月16日、rork-deviceが7月15日、rork-plistが7月13日に更新されましたOPUS46 — RorkでClaude Opus 4.6が稼働しています。Rork MaxはClaude Codeを土台にアプリを組み立てる設計ですSIM — ブラウザ上で動くクラウドのiOSシミュレータを備え、実機へのインストールは1クリック、App Storeへの提出は2クリックと案内されていますMAX — Rork MaxはReact Nativeではなく純粋なSwiftを出力します。iPhone・iPad・Apple Watch・Apple TV・Vision Pro、そしてiMessageまでが射程ですNATIVE — HealthKit、ARKitとLiDAR、NFC、Dynamic Island、Live Activities、Metalによる3D、Core MLのオンデバイス推論まで扱えますSEED — RorkはLeft Lane Capitalが主導する1,500万ドルのシードラウンドを実施し、Peak XVとa16z Speedrunが参加しましたTOOLING — Rorkの開発者向けリポジトリが動き続けています。rork-xcodeが7月16日、rork-deviceが7月15日、rork-plistが7月13日に更新されましたOPUS46 — RorkでClaude Opus 4.6が稼働しています。Rork MaxはClaude Codeを土台にアプリを組み立てる設計ですSIM — ブラウザ上で動くクラウドのiOSシミュレータを備え、実機へのインストールは1クリック、App Storeへの提出は2クリックと案内されていますMAX — Rork MaxはReact Nativeではなく純粋なSwiftを出力します。iPhone・iPad・Apple Watch・Apple TV・Vision Pro、そしてiMessageまでが射程ですNATIVE — HealthKit、ARKitとLiDAR、NFC、Dynamic Island、Live Activities、Metalによる3D、Core MLのオンデバイス推論まで扱えますSEED — RorkはLeft Lane Capitalが主導する1,500万ドルのシードラウンドを実施し、Peak XVとa16z Speedrunが参加しました
記事一覧/開発ツール
開発ツール/2026-05-09中級

Rork で Google サインインの redirect_uri_mismatch が消えない時に確認する5つのこと

Rork アプリで Google サインインを実装したのに「redirect_uri_mismatch」が消えないとき、Google Cloud Console と Expo 側のどこを直せばよいかを5つのチェックポイントで解決します。

troubleshooting25Google Sign-InOAuth2認証14expo-auth-sessionRork515

「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-sessionGoogle.useAuthRequest は内部的にウェブ用クライアント ID を必要とします。これがないと、Expo Go プレビューで動かなかったり、iOS でも特定のフローで失敗したりします。

ウェブ用クライアントの「承認済みのリダイレクト URI」には、最低限以下の 2 つを登録しておきます。

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

your-expo-usernameyour-app-slug は、app.jsonowner フィールドと 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.jsonprebuild 設定で別の 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.jsonschemeInfo.plistCFBundleURLSchemes、そして 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"
            ]
          }
        ]
      }
    }
  }
}

schemeCFBundleURLSchemes を両方設定するのがポイントです。Rork が生成したコードに scheme だけがあって CFBundleURLSchemes が無い場合、iOS 上で認証が成功してもアプリへ戻れず、Safari に取り残されます。

app.json を変更したあとは必ず npx expo prebuild --cleanios/ を再生成し、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 クライアント設定の多くがダッシュボード経由で完結するため、個人開発の効率が大きく上がります。

実装の参考になれば幸いです。同じ場所で詰まっている方の助けになれば嬉しく思います。

シェア

お読みいただきありがとうございます

Rork Lab は広告なしで運営しており、サーバー費用などの運営コストはメンバーシップのご支援で賄っています。実装コード・ベンチマーク・本番設計パターンなど、実務でお役立ていただける記事を毎日更新しています。もし読んでよかったと感じていただけましたら、ぜひご覧ください。

  • コピー&ペーストで使える実装コード付き
  • 毎日新しい上級ガイドを追加
  • ¥580/月 または ¥1,480 の永久アクセス
メンバーシップを見る →

もしこの記事がお役に立ちましたら、チップ(¥150)で応援いただけると大変励みになります。広告なしでの運営を続けるため、皆さまのご支援が大きな力になっています。

関連記事

開発ツール2026-06-21
Rork アプリの認証トークンはどこに保存すべきか — expo-secure-store と生体認証ゲートの設計
Rork で生成したアプリの認証トークンを AsyncStorage から expo-secure-store へ移し、生体認証を読み出しの前段に挟むまでの設計をまとめました。サイズ制限や失効処理など、運用で踏んだ落とし穴も添えています。
開発ツール2026-06-19
Rork アプリの API 通信を堅くする — トークン更新・再試行・冪等性の設計
Rork が生成する fetch はそのままだと、トークン切れ・電波の揺らぎ・二重送信に弱いままです。トークンの自動更新、再試行とバックオフ、冪等性キーを一つのクライアント層に集約する設計を、実装コードと運用の数値とともに整理しました。
開発ツール2026-06-15
Rork で作った Expo アプリのログインを切らさない — トークン更新の競合を単一化で防ぐ
Rork が生成する Expo アプリにログインを足すと、最初は動いても本番でじわじわ「勝手にログアウトされる」報告が増えます。原因の多くはトークン更新の競合です。リフレッシュを単一化し、安全に保存し、失効を正しく扱う信頼性設計を実装視点でまとめます。
📚RECOMMENDED BOOKS
大規模言語モデル入門
山田育矢
LLM開発
生成AIプロンプトエンジニアリング入門
我妻幸長
プロンプト
Claude CodeによるAI駆動開発入門
平川知秀
AI駆動開発
※ アフィリエイトリンクを含みます
もっと見る →