> ## 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>
  この Quickstart は Expo アプリケーション向けです。Auth0 を React Native アプリケーションに統合する場合は、[React Native Quickstart](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
  ```

  **続いて、AI アシスタントに次のように依頼します。**

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

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

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

<Steps>
  <Step title="新しいExpoプロジェクトを作成" stepNumber={1}>
    このQuickstartでは、新しい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 Pluginを設定する" stepNumber={3}>
    ネイティブの iOS および Android の設定を自動的に処理するように、Auth0 プラグインを設定します。

    Auth0 プラグインを含めるために、`app.json` を更新します。

    ```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 domain に置き換えてください (これは次のステップで確認できます) 。

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

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

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

    1. [Auth0 Dashboard](https://manage.auth0.com/dashboard/)に移動します
    2. **アプリケーション** > **アプリケーション** > **Create Application** をクリックします
    3. ポップアップでアプリ名 (例: `Auth0 Expo Sample`) を入力し、アプリの種類として `Native` を選択して **Create** をクリックします
    4. Application Detailsページで **Settings** タブに切り替えます
    5. **Domain** と **Client 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** は、authentication 後にユーザーを安全にアプリケーションへ戻すための重要なセキュリティ対策です。一致する URL がない場合、login は失敗し、ユーザーはアプリにアクセスできず、代わりに Auth0 のエラーページが表示されます。

      **Allowed Logout URLs** は、サインアウト時にシームレスな user experience を提供するうえで不可欠です。一致する URL がない場合、ユーザーは logout 後にアプリケーションへリダイレクトされず、代わりに汎用的な Auth0 ページに移動します。

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

    <Warning>
      **重要**: callback URL 内の `customScheme` が `app.json` の Plugin 設定内の値と完全に一致し、パスに実際の `bundleIdentifier` (iOS) または `package` (Android) が含まれていることを確認してください。値が一致しないと authentication は失敗します。
    </Warning>
  </Step>

  <Step title="アプリコンポーネントを設定する" stepNumber={5}>
    選択した実装方法に合わせて、メインのアプリコンポーネントを設定してください。

    <Tabs>
      <Tab title="フックベース（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 の Client 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
  ```

  ### Callback URL の不一致エラー

  **解決策:**

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

  1. `app.json` のプラグイン設定内の `customScheme`
  2. `authorize()` と `clearSession()` に渡す `customScheme` パラメーター
  3. Auth0 Dashboard の Callback URLs (アプリケーション → Your App → Settings → Application URIs)

  ### "PKCE not allowed" エラー

  **修正方法:**

  1. Auth0 Dashboard → アプリケーション → 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('Login cancelled by user');
      } else {
        console.error('Login failed:', 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('Failed to get credentials', e);
      }
    };
  };
  ```

  <Tip>
    ログイン時に `offline_access` scope を含めると、リフレッシュトークンを受け取れます: `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 callback 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 capability を追加
  * Associated Domains に `webcredentials:{yourDomain}` を追加

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

  * Advanced Settings で **OIDC Conformant** を有効にする
  * **Token Expiration** を適切に設定する
  * **Brute Force Protection** を設定する
  * 複数のデバイスと OS バージョンでテストする
  * ネットワーク障害に備えて適切なエラーハンドリングを実装する

  <Tip>
    本番アプリでは、セキュリティ強化のため、カスタムスキームではなく Universal Links (iOS) や App Links (Android) を使用した HTTPS callback 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)
