> ## Documentation Index
> Fetch the complete documentation index at: https://translations.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Expo アプリケーションにログインを追加する

> このガイドでは、Auth0 React Native SDK を使用して、任意の Expo アプリに Auth0 を統合する方法を説明します。

export const HowToSchema = () => <script type="application/ld+json">
    {'{"@context":"https://schema.org","@type":"HowTo"}'}
  </script>;

<HowToSchema />

<Tip>
  このクイックスタートは Expo アプリケーション向けです。React Native アプリケーションに Auth0 を統合する場合は、[React Native クイックスタート](https://auth0.com/docs/quickstart/native/react-native/interactive)を参照してください。
</Tip>

<Accordion title="AI を使って Auth0 を統合する" icon="microchip-ai" iconType="solid" defaultOpen>
  Claude Code、Cursor、GitHub Copilot などの AI コーディングアシスタントを使用している場合は、[agent skills](https://agentskills.io/home) を使って、数分で Auth0 認証を自動的に追加できます。

  **インストール:**

  ```bash theme={null}
  npx skills add auth0/agent-skills --skill auth0-quickstart --skill auth0-expo
  ```

  **次に、AI アシスタントに次のように依頼します:**

  ```text theme={null}
  Add Auth0 authentication to my Expo app
  ```

  AI アシスタントが、Auth0 アプリケーションの作成、認証情報の取得、react-native-auth0 SDK のインストール、Expo プラグインの設定、ログイン / ログアウトフローの実装を自動的に行います。[agent skills の詳細なドキュメント →](/ja/docs/quickstart/agent-skills)
</Accordion>

<div id="get-started">
  ## はじめに
</div>

<Steps>
  <Step title="新しい Expo プロジェクトを作成する" stepNumber={1}>
    このクイックスタート用に、新しい Expo プロジェクトを作成します。

    **ターミナルで以下を実行します。**

    ```bash theme={null}
    npx create-expo-app Auth0ExpoSample --template blank
    cd Auth0ExpoSample
    ```

    <Tip>
      これにより、最新の SDK を使用した、ネイティブモジュールの統合に対応する最小構成の Expo アプリが作成されます。`--template blank` フラグを使用すると、余分なボイラープレートのないクリーンな開始点が得られます。
    </Tip>

    <Warning>
      この SDK はカスタムネイティブコードを必要とするため、**Expo Go には対応していません**。開発ビルドを作成するには、`npx expo run:ios` または `npx expo run:android` を使用する必要があります。
    </Warning>
  </Step>

  <Step title="Auth0 SDKをインストールする" stepNumber={2}>
    Auth0 React Native SDK をプロジェクトに追加します。

    ```bash theme={null}
    npx expo install react-native-auth0
    ```

    <Tip>
      `npx expo install` を使用すると、Expo SDK のバージョンとの互換性を確保できます。SDK は Expo のプラグインシステムによって自動的に設定されます。
    </Tip>
  </Step>

  <Step title="Expoプラグインを設定する" stepNumber={3}>
    Auth0 プラグインを設定して、ネイティブ iOS および Android の構成を自動的に処理できるようにします。

    `app.json` を更新して、Auth0 プラグインを追加します。

    ```json app.json lines theme={null}
    {
      "expo": {
        "name": "Auth0ExpoSample",
        "slug": "auth0-expo-sample",
        "version": "1.0.0",
        "ios": {
          "bundleIdentifier": "com.auth0.samples.expo",
          "supportsTablet": true
        },
        "android": {
          "package": "com.auth0.samples.expo",
          "adaptiveIcon": {
            "foregroundImage": "./assets/images/adaptive-icon.png",
            "backgroundColor": "#ffffff"
          }
        },
        "plugins": [
          [
            "react-native-auth0",
            {
              "domain": "{yourDomain}",
              "customScheme": "auth0sample"
            }
          ]
        ]
      }
    }
    ```

    `{yourDomain}` をご利用の Auth0 ドメインに置き換えます (これは次の手順で取得します) 。

    <Warning>
      **重要**: `app.json` で、iOS の `bundleIdentifier` と Android の `package` を必ず定義してください。これらの識別子は、Auth0 SDK がネイティブプロジェクトを適切に設定するために必要です。カスタムスキームを指定しない場合、SDK は bundle identifier を URL スキームとして使用します。
    </Warning>

    <Info>
      `customScheme` には小文字のみを使用し、特殊文字は含めないでください。この値はコールバック URL の構築に使用され、`authorize()` メソッドと `clearSession()` メソッドに渡す必要があります。
    </Info>
  </Step>

  <Step title="Auth0アプリケーションを設定する" stepNumber={4}>
    Expo アプリで使用できるように、Auth0 アプリケーションを作成して設定します。

    1. [Auth0 Dashboard](https://manage.auth0.com/dashboard/) に移動します
    2. **Applications** > **Applications** > **Create Application** をクリックします
    3. ポップアップでアプリ名 (例: `Auth0 Expo Sample`) を入力し、アプリの種類として `Native` を選択して **Create** をクリックします
    4. Application Details ページで **Settings** タブを開きます
    5. **ドメイン** と **クライアントID** の値を控えます
    6. `app.json` のプラグイン設定にある `domain` の値を、Auth0 のドメインに更新します

    **Allowed Callback URLs:**

    ```
    auth0sample://{yourDomain}/ios/com.auth0.samples.expo/callback,
    auth0sample://{yourDomain}/android/com.auth0.samples.expo/callback
    ```

    **許可するログアウト URL:**

    ```
    auth0sample://{yourDomain}/ios/com.auth0.samples.expo/callback,
    auth0sample://{yourDomain}/android/com.auth0.samples.expo/callback
    ```

    `{yourDomain}` を実際の Auth0 ドメイン (例: `dev-abc123.us.auth0.com`) に置き換えてください。

    <Info>
      **Allowed Callback URLs** は、認証後にユーザーを安全にアプリケーションへ戻すための重要なセキュリティ対策です。一致する URL がない場合、ログイン処理は失敗し、ユーザーはアプリにアクセスできず、代わりに Auth0 のエラーページが表示されます。

      **Allowed Logout URLs** は、サインアウト時にシームレスなユーザー体験を提供するために不可欠です。一致する URL がない場合、ログアウト後にユーザーはアプリケーションへリダイレクトされず、代わりに汎用的な Auth0 ページが表示されます。

      コールバック URL の形式は `{customScheme}://{yourDomain}/{platform}/{bundleIdentifier or packageName}/callback` です。URL スキームには `app.json` の `customScheme` が使用されますが、パスには常に `bundleIdentifier` (iOS) または `package` (Android) が含まれ、カスタムスキームは含まれません。`customScheme` を指定しない場合、SDK は URL スキームとしてデフォルトで `{bundleIdentifier}.auth0` / `{packageName}.auth0` を使用します。
    </Info>

    <Warning>
      **重要**: コールバック URL の `customScheme` が `app.json` のプラグイン設定内の値と完全に一致し、パスに実際の `bundleIdentifier` (iOS) または `package` (Android) が含まれていることを確認してください。値が一致しないと、認証は失敗します。
    </Warning>
  </Step>

  <Step title="App コンポーネントをセットアップする" stepNumber={5}>
    選択した実装方法に応じて、メインのアプリコンポーネントを設定します。

    <Tabs>
      <Tab title="Hooks ベース（Provider あり）">
        `App.js` の内容を置き換え、アプリケーションを `Auth0Provider` コンポーネントで囲みます。

        ```jsx App.js lines theme={null}
        import React from 'react';
        import {Auth0Provider, useAuth0} from 'react-native-auth0';
        import {
          StyleSheet,
          Text,
          View,
          Button,
          Image,
          ActivityIndicator,
        } from 'react-native';

        function HomeScreen() {
          const {authorize, clearSession, user, isLoading} = useAuth0();

          const handleLogin = async () => {
            try {
              await authorize({customScheme: 'auth0sample', scope: 'openid profile email'});
            } catch (e) {
              console.error('Login error:', e);
            }
          };

          const handleLogout = async () => {
            try {
              await clearSession({customScheme: 'auth0sample'});
            } catch (e) {
              console.error('Logout error:', e);
            }
          };

          if (isLoading) {
            return (
              <View style={styles.container}>
                <ActivityIndicator size="large" color="#0066cc" />
                <Text style={styles.loadingText}>Loading...</Text>
              </View>
            );
          }

          return (
            <View style={styles.container}>
              <Text style={styles.title}>Auth0 Expo Sample</Text>

              {user ? (
                <View style={styles.profileContainer}>
                  {user.picture && (
                    <Image source={{uri: user.picture}} style={styles.avatar} />
                  )}
                  <Text style={styles.welcomeText}>Welcome, {user.name}!</Text>
                  <Text style={styles.emailText}>{user.email}</Text>
                  <View style={styles.buttonContainer}>
                    <Button title="Log Out" onPress={handleLogout} color="#dc3545" />
                  </View>
                </View>
              ) : (
                <View style={styles.loginContainer}>
                  <Text style={styles.subtitle}>
                    Tap the button below to log in
                  </Text>
                  <View style={styles.buttonContainer}>
                    <Button title="Log In" onPress={handleLogin} color="#0066cc" />
                  </View>
                </View>
              )}
            </View>
          );
        }

        export default function App() {
          return (
            <Auth0Provider domain="{yourDomain}" clientId="{yourClientId}">
              <HomeScreen />
            </Auth0Provider>
          );
        }

        const styles = StyleSheet.create({
          container: {
            flex: 1,
            justifyContent: 'center',
            alignItems: 'center',
            padding: 20,
            backgroundColor: '#fff',
          },
          title: {
            fontSize: 28,
            fontWeight: 'bold',
            marginBottom: 20,
            color: '#333',
          },
          subtitle: {
            fontSize: 16,
            color: '#666',
            marginBottom: 30,
            textAlign: 'center',
          },
          loadingText: {
            marginTop: 10,
            fontSize: 16,
            color: '#666',
          },
          profileContainer: {
            alignItems: 'center',
          },
          avatar: {
            width: 100,
            height: 100,
            borderRadius: 50,
            marginBottom: 20,
          },
          welcomeText: {
            fontSize: 22,
            fontWeight: '600',
            marginBottom: 8,
            color: '#333',
          },
          emailText: {
            fontSize: 16,
            color: '#666',
            marginBottom: 30,
          },
          loginContainer: {
            alignItems: 'center',
          },
          buttonContainer: {
            width: 200,
            marginTop: 10,
          },
        });
        ```

        `{yourDomain}` は Auth0 のドメインに、`{yourClientId}` は Auth0 Dashboard のクライアントIDに置き換えます。

        <Tip>
          `Auth0Provider` は SDK を初期化し、`useAuth0` フックを通じてすべての子コンポーネントに認証コンテキストを提供します。`customScheme` パラメーターは、`app.json` のプラグイン設定の値と一致する必要があります。
        </Tip>
      </Tab>

      <Tab title="クラスベース（Provider なし）">
        `App.js` の内容をクラスベースのコンポーネントに置き換えます：

        ```jsx App.js lines theme={null}
        import React, {Component} from 'react';
        import {
          View,
          Text,
          Button,
          StyleSheet,
          ActivityIndicator,
          Image,
        } from 'react-native';
        import Auth0, {Credentials} from 'react-native-auth0';

        const auth0 = new Auth0({
          domain: '{yourDomain}',
          clientId: '{yourClientId}',
        });

        interface User {
          name?: string;
          email?: string;
          picture?: string;
        }

        interface AppState {
          user: User | null;
          isLoading: boolean;
        }

        class App extends Component<{}, AppState> {
          constructor(props: {}) {
            super(props);
            this.state = {
              user: null,
              isLoading: true,
            };
          }

          async componentDidMount() {
            await this.checkAuthStatus();
          }

          checkAuthStatus = async () => {
            try {
              const hasValidCredentials = await auth0.credentialsManager.hasValidCredentials();
              if (hasValidCredentials) {
                const credentials = await auth0.credentialsManager.getCredentials();
                const userInfo = await auth0.auth.userInfo({token: credentials.accessToken});
                this.setState({user: userInfo, isLoading: false});
              } else {
                this.setState({isLoading: false});
              }
            } catch (e) {
              console.error(e);
              this.setState({isLoading: false});
            }
          };

          login = async () => {
            try {
              const credentials: Credentials = await auth0.webAuth.authorize({
                scope: 'openid profile email',
              }, {customScheme: 'auth0sample'});
              
              await auth0.credentialsManager.saveCredentials(credentials);
              const userInfo = await auth0.auth.userInfo({token: credentials.accessToken});
              this.setState({user: userInfo});
            } catch (e) {
              console.error(e);
            }
          };

          logout = async () => {
            try {
              await auth0.webAuth.clearSession({}, {customScheme: 'auth0sample'});
              await auth0.credentialsManager.clearCredentials();
              this.setState({user: null});
            } catch (e) {
              console.error(e);
            }
          };

          render() {
            const {user, isLoading} = this.state;

            if (isLoading) {
              return (
                <View style={styles.container}>
                  <ActivityIndicator size="large" color="#0066cc" />
                  <Text style={styles.loadingText}>Loading...</Text>
                </View>
              );
            }

            return (
              <View style={styles.container}>
                <Text style={styles.title}>Auth0 Expo Sample</Text>

                {user ? (
                  <View style={styles.profileContainer}>
                    {user.picture && (
                      <Image source={{uri: user.picture}} style={styles.avatar} />
                    )}
                    <Text style={styles.welcomeText}>Welcome, {user.name}!</Text>
                    <Text style={styles.emailText}>{user.email}</Text>
                    <View style={styles.buttonContainer}>
                      <Button title="Log Out" onPress={this.logout} color="#dc3545" />
                    </View>
                  </View>
                ) : (
                  <View style={styles.loginContainer}>
                    <Text style={styles.subtitle}>
                      Tap the button below to log in
                    </Text>
                    <View style={styles.buttonContainer}>
                      <Button title="Log In" onPress={this.login} color="#0066cc" />
                    </View>
                  </View>
                )}
              </View>
            );
          }
        }

        const styles = StyleSheet.create({
          container: {
            flex: 1,
            justifyContent: 'center',
            alignItems: 'center',
            padding: 20,
            backgroundColor: '#fff',
          },
          title: {
            fontSize: 28,
            fontWeight: 'bold',
            marginBottom: 20,
            color: '#333',
          },
          subtitle: {
            fontSize: 16,
            color: '#666',
            marginBottom: 30,
            textAlign: 'center',
          },
          loadingText: {
            marginTop: 10,
            fontSize: 16,
            color: '#666',
          },
          profileContainer: {
            alignItems: 'center',
          },
          avatar: {
            width: 100,
            height: 100,
            borderRadius: 50,
            marginBottom: 20,
          },
          welcomeText: {
            fontSize: 22,
            fontWeight: '600',
            marginBottom: 8,
            color: '#333',
          },
          emailText: {
            fontSize: 16,
            color: '#666',
            marginBottom: 30,
          },
          loginContainer: {
            alignItems: 'center',
          },
          buttonContainer: {
            width: 200,
            marginTop: 10,
          },
        });

        export default App;
        ```

        `{yourDomain}` をAuth0のドメインに、`{yourClientId}` をAuth0 DashboardのクライアントIDに置き換えてください。

        <Tip>
          クラスベースのアプローチでは、`Auth0` クラスのインスタンスを直接使用するため、`Auth0Provider` は不要です。`customScheme` オプションは、`authorize()` と `clearSession()` の第2引数として渡す必要があります。
        </Tip>
      </Tab>
    </Tabs>

    <Info>
      `authorize()` メソッドは、安全なブラウザー (iOS では ASWebAuthenticationSession、Android では Chrome Custom Tabs) で Auth0 の Universal Login を開きます。`clearSession()` メソッドはユーザーをログアウトし、ブラウザーのセッションと保存された認証情報の両方を消去します。`customScheme` パラメーターは、`app.json` のプラグイン設定の値と一致している必要があります。
    </Info>
  </Step>

  <Step title="アプリを実行する" stepNumber={6}>
    Expo アプリをデバイスまたはエミュレーターでビルドして実行します。

    **まず、ネイティブの iOS プロジェクトと Android プロジェクトを生成します。**

    ```bash theme={null}
    npx expo prebuild
    ```

    **次に、対象プラットフォームで実行します。**

    **iOS の場合:**

    ```bash theme={null}
    npx expo run:ios
    ```

    **Android の場合:**

    ```bash theme={null}
    npx expo run:android
    ```

    **想定されるフロー:**

    1. アプリが起動し、"Log In" ボタンが表示される
    2. **Log In** をタップ → Auth0 Universal Login をブラウザーで開く
    3. ログインを完了する (サインアップまたはサインイン)
    4. ブラウザーが閉じる → 自動的にアプリに戻る
    5. 名前、メールアドレス、アバターを含むユーザープロフィールが表示される

    <Tip>
      `app.json` のプラグイン設定を変更した場合は、`npx expo prebuild --clean` を実行して、更新後の設定でネイティブプロジェクトを再生成してください。
    </Tip>

    <Warning>
      iOS Simulator で ASWebAuthenticationSession を使用するには、有効な Apple Developer アカウントが必要です。アカウントなしでシミュレーター上でテストする場合は、代わりに実機または Android エミュレーターを使用してください。
    </Warning>
  </Step>
</Steps>

<Check>
  **チェックポイント**

  これで、デバイスまたはエミュレーター上で Auth0 のログイン機能が完全に動作しているはずです。このアプリは安全なブラウザー認証を使用し、認証情報をデバイスのセキュアストレージで自動的に管理します。
</Check>

***

<div id="troubleshooting-advanced">
  ## トラブルシューティングと高度な設定
</div>

<Accordion title="よくある問題と解決策">
  ### "Invariant Violation: Native module cannot be null"

  このエラーは、Expo Go で SDK を使用しようとすると発生します。

  **解決策:**

  Auth0 SDK では、Expo Go では利用できないカスタムネイティブコードが必要です。代わりに開発用ビルドを使用してください。

  ```bash theme={null}
  npx expo run:ios
  # または
  npx expo run:android
  ```

  ### コールバック URL の不一致エラー

  **解決策:**

  次の 3 つがすべて完全に一致していることを確認してください。

  1. `app.json` のプラグイン設定内の `customScheme`
  2. `authorize()` と `clearSession()` に渡す `customScheme` パラメーター
  3. Auth0 Dashboard のコールバック URL (Applications → Your App → Settings → Application URIs)

  ### "PKCE not allowed" エラー

  **修正方法:**

  1. Auth0 Dashboard → Applications → Your Application に移動します
  2. アプリケーションタイプを **Native** に変更します
  3. 変更を保存して、再度試してください

  ### Prebuild が失敗する、またはプラグインが適用されない

  **修正方法:**

  ```bash theme={null}
  # ネイティブプロジェクトをクリーンアップして再生成
  npx expo prebuild --clean
  ```

  ### iOS ビルドが Pod エラーで失敗する

  **修正方法:**

  ```bash theme={null}
  cd ios
  pod install --repo-update
  cd ..
  npx expo run:ios
  ```

  ### ユーザーによるキャンセル エラー

  ログイン関数で適切に処理してください。

  ```jsx expandable theme={null}
  const handleLogin = async () => {
    try {
      await authorize({customScheme: 'auth0sample', scope: 'openid profile email'});
    } catch (e) {
      if (e.message === 'a0.session.user_cancelled') {
        // ユーザーがログイン画面を閉じた場合の処理
        console.log('ユーザーによってログインがキャンセルされました');
      } else {
        console.error('ログインに失敗しました:', e);
      }
    }
  };
  ```

  ### iOS のアラートダイアログ

  iOS では、*"App Name" Wants to Use "auth0.com" to Sign In* という許可ダイアログが表示されます。これは `ASWebAuthenticationSession` の想定された動作です。続行するには、ユーザーが **Continue** をタップする必要があります。

  この動作を変更するには、エフェメラルセッションを使用できます (SSO は無効になります) 。

  ```jsx theme={null}
  await authorize({customScheme: 'auth0sample', scope: 'openid profile email'}, {ephemeralSession: true});
  ```
</Accordion>

<Accordion title="アクセストークンの取得">
  API 呼び出しに使用するトークンを取得するには、`getCredentials()` メソッドを使用します。

  ```jsx expandable lines theme={null}
  import {useAuth0} from 'react-native-auth0';

  const MyComponent = () => {
    const {getCredentials} = useAuth0();

    const callApi = async () => {
      try {
        const credentials = await getCredentials();
        const response = await fetch('https://your-api.com/endpoint', {
          headers: {
            Authorization: `Bearer ${credentials.accessToken}`,
          },
        });
        // レスポンスを処理
      } catch (e) {
        console.error('認証情報の取得に失敗しました', e);
      }
    };
  };
  ```

  <Tip>
    リフレッシュトークンを受け取るには、ログイン時に `offline_access` スコープを含めてください: `authorize({customScheme: 'auth0sample', scope: 'openid profile email offline_access'})`。これにより、トークンの自動更新が有効になります。
  </Tip>
</Accordion>

<Accordion title="アプリ起動時に認証状態を確認する">
  ユーザーがすでにログインしているかどうかを確認するには、`hasValidCredentials()` を使用します。

  ```jsx expandable lines theme={null}
  import {useAuth0} from 'react-native-auth0';
  import {useEffect} from 'react';

  const App = () => {
    const {hasValidCredentials, getCredentials} = useAuth0();

    useEffect(() => {
      const checkAuth = async () => {
        const isLoggedIn = await hasValidCredentials();
        if (isLoggedIn) {
          const credentials = await getCredentials();
          // ユーザーは認証済みのため、そのデータを読み込む
        }
      };
      checkAuth();
    }, []);
  };
  ```
</Accordion>

<Accordion title="EAS Build を使用した本番環境へのデプロイ">
  本番ビルドでは、ローカルの開発ビルドではなく EAS Build を使用します。

  **EAS CLI をインストールします。**

  ```bash theme={null}
  npm install -g eas-cli
  ```

  **プロジェクトのルートに `eas.json` を作成します。**

  ```json eas.json lines theme={null}
  {
    "cli": {
      "version": ">= 3.0.0"
    },
    "build": {
      "development": {
        "developmentClient": true,
        "distribution": "internal"
      },
      "preview": {
        "distribution": "internal"
      },
      "production": {}
    }
  }
  ```

  **本番用にビルドします。**

  ```bash theme={null}
  # 両方のプラットフォーム向けにビルド
  eas build --platform all

  # または特定のプラットフォーム向けにビルド
  eas build --platform ios
  eas build --platform android
  ```

  ### 本番環境にデプロイする前に

  セキュリティを強化するため、**HTTPS コールバック URL** を使用します。

  ```text theme={null}
  https://{yourDomain}/ios/{bundleId}/callback
  https://{yourDomain}/android/{packageName}/callback
  ```

  Auth0 Dashboard で **Android App Links** を設定します。

  * Settings → Advanced Settings → Device Settings
  * アプリの SHA-256 フィンガープリントを追加します

  **iOS Universal Links** を設定します。

  * Xcode で Associated Domains 機能を追加します
  * Associated Domains に `webcredentials:{yourDomain}` を追加します

  Auth0 Dashboard で **セキュリティ設定** を確認します。

  * Advanced Settings で **OIDC Conformant** を有効にします
  * **トークンの有効期限** を適切に設定します
  * **総当たり攻撃対策** を設定します
  * 複数のデバイスと OS バージョンでテストします
  * ネットワーク障害に対する適切なエラーハンドリングを実装します

  <Tip>
    本番アプリでは、セキュリティ強化のため、カスタムスキームではなく、Universal Links (iOS) や App Links (Android) を使用する HTTPS コールバック URL の利用を検討してください。
  </Tip>
</Accordion>

* [サンプルアプリケーション](https://github.com/auth0-samples/auth0-react-native-sample/tree/master/00-Login-Expo)
* [移行ガイド (v4 から v5) ](https://github.com/auth0/react-native-auth0/blob/master/MIGRATION_GUIDE.md)
