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

# iOS または macOS アプリケーションにログイン機能を追加する

export const AuthCodeGroup = ({children, dropdown}) => {
  const [processedChildren, setProcessedChildren] = useState(children);
  useEffect(() => {
    let unsubscribe = null;
    function init() {
      unsubscribe = window.autorun(() => {
        const processChildren = node => {
          if (typeof node === "string") {
            let processedNode = node;
            for (const [key, value] of window.rootStore.variableStore.values.entries()) {
              processedNode = processedNode.replace(new RegExp(key, "g"), value);
            }
            return processedNode;
          } else if (Array.isArray(node)) {
            return node.map(processChildren);
          } else if (node && node.props && node.props.children) {
            return {
              ...node,
              props: {
                ...node.props,
                children: processChildren(node.props.children)
              }
            };
          }
          return node;
        };
        setProcessedChildren(processChildren(children));
      });
    }
    if (window.rootStore) {
      init();
    } else {
      window.addEventListener("adu:storeReady", init);
    }
    return () => {
      window.removeEventListener("adu:storeReady", init);
      unsubscribe?.();
    };
  }, [children]);
  return <CodeGroup dropdown={dropdown}>{processedChildren}</CodeGroup>;
};

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

<Steps>
  <Step title="新しいプロジェクトを作成" stepNumber={1}>
    このクイックスタート用に新しい iOS または macOS プロジェクトを作成してください。

    **Xcode で:**

    1. **File** → **New** → **Project**（または **⌘+Shift+N**）
    2. 次のいずれかを選択します:
       * **iOS** タブ → **App** テンプレート
       * **macOS** タブ → **App** テンプレート
    3. プロジェクトを設定します:
       * **Product Name**: `Auth0-Sample`
       * **Interface**: SwiftUI
       * **Language**: Swift
       * **Use Core Data**: チェックを外す
       * **Include Tests**: チェックを入れる（推奨）
    4. 保存場所を選択し、**Create** をクリックします

    <Tip>
      これにより、SwiftUI を使用し Swift Package Manager に対応した標準的なアプリが作成され、Auth0 を統合するのに最適です。
    </Tip>
  </Step>

  <Step title="Auth0 SDK を追加する" stepNumber={2}>
    Auth0 ソフトウェア開発キット (SDK) を、好みのパッケージマネージャーを使ってプロジェクトに追加します。

    <Tabs>
      <Tab title="Swift Package Manager">
        **Xcode で:**

        1. **File** → **Add Package Dependencies...**（または **⌘+Shift+K**）
        2. Auth0 SDK の URL を入力します:
           ```
           https://github.com/auth0/Auth0.swift
           ```
        3. **Add Package** → アプリのターゲットを選択 → **Add Package**
      </Tab>

      <Tab title="CocoaPods">
        1. プロジェクトディレクトリに `Podfile` を作成します:
           ```ruby Podfile theme={null}
           platform :ios, '14.0' # macOS の場合は platform :osx, '11.0'
           use_frameworks!

           target 'YourApp' do
             pod 'Auth0', '~> 2.0'
           end
           ```
        2. 依存関係をインストールします:
           ```bash theme={null}
           pod install
           ```
        3. 生成された `.xcworkspace` ファイルを開きます（`.xcodeproj` ではありません）
      </Tab>

      <Tab title="Carthage">
        1. プロジェクトディレクトリに `Cartfile` を作成します:
           ```text Cartfile theme={null}
           github "auth0/Auth0.swift" ~> 2.0
           ```
        2. Carthage を実行します:
           ```bash theme={null}
           carthage update --platform iOS --use-xcframeworks
           ```
           macOS の場合は `--platform macOS` を使用します
        3. 生成された `Auth0.xcframework` を `Carthage/Build` から Xcode プロジェクトにドラッグします
        4. ターゲットの **General** 設定で、**Frameworks, Libraries, and Embedded Content** に `Auth0.xcframework` を追加します
      </Tab>
    </Tabs>
  </Step>

  <Step title="Auth0 を設定する" stepNumber={3}>
    新しい Auth0 アプリケーションを作成して、コールバックURLを設定します。

    1. [Auth0 Dashboard](https://manage.auth0.com/dashboard/) にアクセスします
    2. **Applications** > **Create Application** に進み、名前を入力して **Native** を選択し、**Create** をクリックします
    3. **Settings** タブで、**Client ID** と **Domain** を確認しておきます
    4. 次のURLを **Allowed Callback URLs** に追加します:

    <Tabs>
      <Tab title="iOS">
        ```
        https://{yourDomain}/ios/YOUR_BUNDLE_IDENTIFIER/callback,
        YOUR_BUNDLE_IDENTIFIER://{yourDomain}/ios/YOUR_BUNDLE_IDENTIFIER/callback
        ```
      </Tab>

      <Tab title="macOS">
        ```
        https://{yourDomain}/macos/YOUR_BUNDLE_IDENTIFIER/callback,
        YOUR_BUNDLE_IDENTIFIER://{yourDomain}/macos/YOUR_BUNDLE_IDENTIFIER/callback
        ```
      </Tab>
    </Tabs>

    5. 次のURLを **Allowed Logout URLs** に追加します:

    <Tabs>
      <Tab title="iOS">
        ```
        https://{yourDomain}/ios/YOUR_BUNDLE_IDENTIFIER/callback,
        YOUR_BUNDLE_IDENTIFIER://{yourDomain}/ios/YOUR_BUNDLE_IDENTIFIER/callback
        ```
      </Tab>

      <Tab title="macOS">
        ```
        https://{yourDomain}/macos/YOUR_BUNDLE_IDENTIFIER/callback,
        YOUR_BUNDLE_IDENTIFIER://{yourDomain}/macos/YOUR_BUNDLE_IDENTIFIER/callback
        ```
      </Tab>
    </Tabs>

    6. **Save Changes** をクリックします
  </Step>

  <Step title="アプリケーションクレデンシャルの設定" stepNumber={4}>
    プロジェクトディレクトリに `Auth0.plist` ファイルを作成します。

    ```xml Auth0.plist theme={null}
    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
    <plist version="1.0">
    <dict>
        <key>ClientId</key>
        <string>YOUR_AUTH0_CLIENT_ID</string>
        <key>Domain</key>
        <string>{yourDomain}</string>
    </dict>
    </plist>
    ```

    `Auth0.plist` を Xcode にドラッグし、「Add to target」にチェックが付いていることを確認してください。
  </Step>

  <Step title="認証サービスの作成" stepNumber={5}>
    `AuthenticationService.swift` を作成します。

    1. プロジェクトを右クリックし、**New File...** → **Swift File** を選択します
    2. ファイル名を `AuthenticationService` にします
    3. 内容を次のコードに置き換えます：

    ```swift AuthenticationService.swift expandable lines theme={null}
    import Foundation
    import Auth0
    import Combine

    @MainActor
    class AuthenticationService: ObservableObject {
        @Published var isAuthenticated = false
        @Published var user: User?
        @Published var isLoading = false
        @Published var errorMessage: String?
        
        private let credentialsManager = CredentialsManager(authentication: Auth0.authentication())
        
        init() {
            Task {
                await checkAuthenticationStatus()
            }
        }
        
        private func checkAuthenticationStatus() async {
            isLoading = true
            defer { isLoading = false }
            
            guard let credentials = try? await credentialsManager.credentials() else {
                isAuthenticated = false
                return
            }
            
            isAuthenticated = true
            // IDトークンからユーザー情報を取得
            user = credentials.user
        }
        
        func login() async {
            isLoading = true
            errorMessage = nil
            defer { isLoading = false }
            
            do {
                let credentials = try await Auth0
                    .webAuth()
                    .scope("openid profile email offline_access")
                    .start()
                
                _ = credentialsManager.store(credentials: credentials)
                isAuthenticated = true
                // IDトークンからユーザー情報を取得
                user = credentials.user
            } catch {
                errorMessage = "ログインに失敗しました: \(error.localizedDescription)"
            }
        }
        
        func logout() async {
            isLoading = true
            defer { isLoading = false }
            
            do {
                try await Auth0.webAuth().clearSession()
                _ = credentialsManager.clear()
                isAuthenticated = false
                user = nil
            } catch {
                errorMessage = "ログアウトに失敗しました: \(error.localizedDescription)"
            }
        }
    }
    ```
  </Step>

  <Step title="UI コンポーネントの作成" stepNumber={6}>
    UI ファイルを作成してコードを追加する

    ```bash theme={null}
    touch AuthenticatedView.swift UnauthenticatedView.swift ProfileCard.swift LoadingView.swift
    ```

    <AuthCodeGroup>
      ```swift ContentView.swift expandable lines theme={null}
      import SwiftUI

      struct ContentView: View {
          @StateObject private var authService = AuthenticationService()
          
          var body: some View {
              VStack(spacing: 30) {
                  Image(systemName: "shield.checkered")
                      .font(.system(size: 80))
                      .foregroundStyle(.blue)
                  
                  Text("Auth0 サンプル")
                      .font(.largeTitle)
                      .fontWeight(.bold)
                  
                  if authService.isLoading {
                      LoadingView()
                  } else if authService.isAuthenticated {
                      AuthenticatedView(authService: authService)
                  } else {
                      UnauthenticatedView(authService: authService)
                  }
                  
                  Spacer()
              }
              .padding()
              .alert("エラー", isPresented: .constant(authService.errorMessage != nil)) {
                  Button("OK") { authService.errorMessage = nil }
              } message: {
                  Text(authService.errorMessage ?? "")
              }
          }
      }
      ```

      ```swift AuthenticatedView.swift expandable lines theme={null}
      import SwiftUI

      struct AuthenticatedView: View {
          @ObservedObject var authService: AuthenticationService
          
          var body: some View {
              VStack(spacing: 24) {
                  HStack {
                      Image(systemName: "checkmark.circle.fill")
                          .foregroundColor(.green)
                      Text("認証に成功しました！")
                          .font(.headline)
                          .foregroundColor(.green)
                  }
                  .padding()
                  .background(Color.green.opacity(0.1))
                  .cornerRadius(12)
                  
                  Text("あなたのプロファイル")
                      .font(.title2)
                      .fontWeight(.semibold)
                  
                  ProfileCard(user: authService.user)
                  
                  Button("ログアウト") {
                      Task {
                          await authService.logout()
                      }
                  }
                  .buttonStyle(.borderedProminent)
                  .controlSize(.large)
                  .disabled(authService.isLoading)
              }
          }
      }
      ```

      ```swift UnauthenticatedView.swift expandable lines theme={null}
      import SwiftUI

      struct UnauthenticatedView: View {
          @ObservedObject var authService: AuthenticationService
          
          var body: some View {
              VStack(spacing: 24) {
                  Text("アカウントにサインインして始めましょう")
                      .font(.title3)
                      .multilineTextAlignment(.center)
                      .foregroundColor(.secondary)
                      .padding()
                      .background(Color(.secondarySystemBackground))
                      .cornerRadius(16)
                  
                  Button("ログイン") {
                      Task {
                          await authService.login()
                      }
                  }
                  .buttonStyle(.borderedProminent)
                  .controlSize(.large)
                  .disabled(authService.isLoading)
              }
          }
      }
      ```

      ```swift ProfileCard.swift expandable lines theme={null}
      import SwiftUI
      import Auth0

      struct ProfileCard: View {
          let user: User?
          
          var body: some View {
              VStack(spacing: 16) {
                  if let user = user {
                      AsyncImage(url: URL(string: user.picture ?? "")) { image in
                          image.resizable().aspectRatio(contentMode: .fill)
                      } placeholder: {
                          Image(systemName: "person.circle.fill")
                              .font(.system(size: 80))
                              .foregroundColor(.gray)
                      }
                      .frame(width: 100, height: 100)
                      .clipShape(Circle())
                      
                      VStack(spacing: 8) {
                          if let name = user.name {
                              Text(name).font(.title2).fontWeight(.semibold)
                          }
                          if let email = user.email {
                              Text(email).foregroundColor(.secondary)
                          }
                      }
                  } else {
                      ProgressView()
                      Text("プロファイルを読み込み中...").foregroundColor(.secondary)
                  }
              }
              .padding()
              .background(Color(.tertiarySystemBackground))
              .cornerRadius(16)
          }
      }
      ```

      ```swift LoadingView.swift expandable lines theme={null}
      import SwiftUI

      struct LoadingView: View {
          var body: some View {
              VStack(spacing: 16) {
                  ProgressView().scaleEffect(1.2)
                  Text("読み込み中...").font(.headline).foregroundColor(.secondary)
              }
          }
      }
      ```
    </AuthCodeGroup>
  </Step>

  <Step title="認証フローの設定（任意）" stepNumber={7}>
    ユーザーエクスペリエンスを向上させるために、次の方法でシステムアラートを最小限に抑えることができます。

    1. ユニバーサルリンクを使用する: リダイレクト中に表示される「"AppName" で開きますか？」というプロンプトをなくします。注: ASWebAuthenticationSession の許可アラートは引き続き表示されます。
    2. エフェメラルセッションを使用する: すべての許可アラートをなくします。注: Single Sign-On (SSO) と共有 Cookie が無効になります。

    <Tip>
      許可アラートありのデフォルトの動作を使用する場合は、**この手順をスキップ**してください。この設定は後から行うこともできます。
    </Tip>

    <Tabs>
      <Tab title="ユニバーサルリンク">
        1. Auth0 Dashboard → **Applications** → 対象のアプリ → **Settings** → **Advanced Settings** → **Device Settings**
        2. **Apple Team ID** と **bundle identifier** を追加 → **Save**
        3. Xcode: Target → **Signing & Capabilities** → **+ Capability** → **Associated Domains**
        4. `webcredentials:{yourDomain}` を追加

        <Warning>要件: 有料の Apple Developer アカウント、iOS 17.4+/macOS 14.4+</Warning>

        <Tip>
          本番アプリに最適です。
        </Tip>
      </Tab>

      <Tab title="エフェメラルセッション">
        `.useEphemeralSession()` を `AuthenticationService.swift` のログイン呼び出しに追加します:

        ```swift theme={null}
        // login() 関数内
        let credentials = try await Auth0
            .webAuth()
            .scope("openid profile email offline_access")
            .useEphemeralSession()
            .start()
        ```

        <Info>
          エフェメラルセッションを使用する場合、ログアウト時に `clearSession()` を呼び出す必要はありません。アプリから資格情報をクリアするだけで問題ありません。削除する共有 Cookie は存在しません。
        </Info>

        <Tip>
          すばやくセットアップでき、アラートも表示されませんが、その代わりユーザーは毎回ログインする必要があります（SSO なし）。
        </Tip>
      </Tab>
    </Tabs>
  </Step>

  <Step title="アプリを実行する" stepNumber={8}>
    Xcode で **⌘+R** キーを押します。

    1. "Log In" をタップ → （デフォルト設定を使用している場合）アクセス許可のアラート → "Continue" をタップ
    2. ブラウザでログインを完了します
    3. プロファイルが表示されます！
  </Step>
</Steps>

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

  これで、iOS または macOS アプリに Auth0 によるログイン機能が完全に実装されました。
</Check>

***

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

<Accordion title="一般的な問題と解決策">
  <div id="build-errors-auth0-module-not-found">
    ### ビルドエラー: 'Auth0' モジュールが見つかりません
  </div>

  **解決策**:

  1. **Swift Package Manager**: **Package Dependencies** を確認し、`Auth0.swift` が一覧に含まれていることを確認する
  2. **CocoaPods**: `.xcodeproj` ではなく `.xcworkspace` ファイルを開いていることを確認する
  3. **Carthage**: `Auth0.xcframework` が **Frameworks, Libraries, and Embedded Content** に追加されていることを確認する
  4. クリーンして再ビルド: **⌘+Shift+K** の後に **⌘+R**
  5. 必要であれば Xcode を再起動する

  <div id="app-crashes-auth0plist-not-found">
    ### アプリがクラッシュする: 'Auth0.plist not found'
  </div>

  **対処方法**:

  1. `Auth0.plist` が Xcode のプロジェクトナビゲーターに含まれていることを確認する
  2. ファイルを選択 → Inspector → アプリのターゲットにチェックが入っていることを確認する
  3. `ClientId` と `Domain` キーに、ご自身の値が設定されていることを確認する
  4. **代替案**: プログラムによる設定を使用する（下記の「高度な統合」セクションを参照）

  <div id="browser-opens-but-never-returns-to-app">
    ### ブラウザは開くがアプリに戻ってこない
  </div>

  **対処方法**:

  1. Auth0 Dashboard のコールバック URL が、バンドル識別子およびプラットフォームと完全に一致していることを確認する
  2. iOS の場合: URL には `/ios/` を含める。macOS の場合: `/macos/` を含める
  3. Xcode のバンドル識別子が Auth0 の設定と一致していることを確認する
  4. URL にタイプミスがないことを確認する（よくある例: コロン抜け、ドメイン形式の誤り）
  5. **カスタムドメイン利用時**: Auth0 のドメインではなく、自身のカスタムドメインを使用していることを確認する

  <div id="permission-alert-appears-every-time">
    ### 毎回パーミッションアラートが表示される
  </div>

  これはカスタム URL スキーム使用時の、標準的な iOS/macOS のセキュリティ動作です。ユニバーサルリンクまたはエフェメラルセッションを使用してこのアラートを解消するには、**ステップ 6** を参照してください。
</Accordion>

<Accordion title="カスタムドメインの設定">
  [カスタムドメイン](/customize/custom-domains) を使用している場合は、Auth0 のドメインの代わりに、その値をすべての箇所で使用してください。

  **例:** `tenant.auth0.com` の代わりに `login.example.com` を使用する

  これは、特定の機能を正しく動作させるには **必須** です:

  * `Auth0.plist` をカスタムドメインで更新する
  * コールバック URL / ログアウト URL にカスタムドメインを使用する
  * ユニバーサルリンクでは `webcredentials:login.example.com` を使用する
</Accordion>

<Accordion title="本番環境へのデプロイ">
  <div id="app-store-preparation">
    ### App Store への準備
  </div>

  * パーミッションアラートをなくすためにユニバーサルリンクを設定する
  * 複数のプラットフォームバージョンおよびデバイスサイズでテストする
  * ネットワーク障害に対する適切なエラー処理を実装する
  * 生体認証付きで Keychain を使用する場合は、プライバシー使用目的の説明を追加する
  * 認証フローに関して App Store Review ガイドラインに従う

  <div id="security-best-practices">
    ### セキュリティのベストプラクティス
  </div>

  * 本番環境では機密性の高い認証データをログに出力しない
  * App Transport Security (ATS) に準拠する
  * すべてのネットワークリクエストで HTTPS を使用する
  * Auth0 の API 証明書を **ピン留めしないでください** - [Auth0 はこの手法を推奨していません](/troubleshoot/product-lifecycle/past-migrations#avoid-pinning-or-fingerprinting-tls-certificates-for-auth0-endpoints)

  <div id="performance-optimization">
    ### パフォーマンス最適化
  </div>

  * すべての非同期処理で、UI 更新には `@MainActor` を正しく使用する
  * `@Published` プロパティで適切なメモリ管理を行う
  * 資格情報をオフラインアクセス用に Keychain に安全にキャッシュする
  * ユーザーのプロファイルは IDトークンから取得し、追加のネットワークリクエストは発生させない
</Accordion>

<Accordion title="高度な統合">
  <div id="programmatic-configuration">
    ### プログラムによる構成
  </div>

  `Auth0.plist` を使用する代わりに、認証情報をコード内で直接渡すこともできます。これは、認証情報を動的にしたい場合や、環境ごと（例: 開発 / ステージング / 本番で別々の Auth0 テナントを使用する場合）に切り替えたい場合に便利です。

  **`Auth0.webAuth()` の呼び出しを `Auth0.webAuth(clientId:domain:)` に置き換えます:**

  ```swift theme={null}
  // AuthenticationService.swift 内 - login 関数
  func login() async {
      isLoading = true
      errorMessage = nil
      defer { isLoading = false }
      
      do {
          let credentials = try await Auth0
              .webAuth(clientId: "{yourClientId}", domain: "{yourDomain}")
              .scope("openid profile email offline_access")
              .start()
          
          _ = credentialsManager.store(credentials: credentials)
          isAuthenticated = true
          user = credentials.user
      } catch {
          errorMessage = "Login failed: \(error.localizedDescription)"
      }
  }

  // AuthenticationService.swift 内 - logout 関数
  func logout() async {
      isLoading = true
      defer { isLoading = false }
      
      do {
          try await Auth0.webAuth(clientId: "{yourClientId}", domain: "{yourDomain}").clearSession()
          _ = credentialsManager.clear()
          isAuthenticated = false
          user = nil
      } catch {
          errorMessage = "Logout failed: \(error.localizedDescription)"
      }
  }
  ```

  <div id="enhanced-keychain-security-with-biometrics">
    ### 生体認証による Keychain セキュリティの強化
  </div>

  保存された認証情報へアクセスする際に、Face ID または Touch ID を必須にします:

  ```swift theme={null}
  private let credentialsManager: CredentialsManager = {
      let manager = CredentialsManager(authentication: Auth0.authentication())
      manager.enableBiometrics(
          withTitle: "Unlock with Face ID", 
          cancelTitle: "Cancel", 
          fallbackTitle: "Use Passcode"
      )
      return manager
  }()
  ```

  有効にすると、SDK が保存された認証情報を取得する前に、ユーザーは生体認証で認証する必要があります。

  <div id="automatic-token-refresh">
    ### アクセストークンの自動リフレッシュ
  </div>

  `CredentialsManager` は、有効期限が切れたアクセストークンを自動的に更新します:

  ```swift theme={null}
  // 認証情報の取得 - 有効期限切れの場合は自動的にリフレッシュされる
  func getAccessToken() async throws -> String {
      let credentials = try await credentialsManager.credentials()
      return credentials.accessToken
  }
  ```

  アクセストークンが必要な API 呼び出しを行う場合は、このパターンを使用してください。

  <div id="shared-credentials-across-app-extensions">
    ### App Extension 間での認証情報共有
  </div>

  ウィジェット、App Extension、バックグラウンドタスクなどでアクセストークンが必要な場合:

  ```swift theme={null}
  // App Group を利用した共有 CredentialsManager の作成
  let credentialsManager = CredentialsManager(
      authentication: Auth0.authentication(),
      storeKey: "credentials",
      storage: .shared(withIdentifier: "group.com.example.myapp")
  )
  ```

  **要件:**

  1. すべてのターゲットで Xcode の **App Groups** 機能を有効化する
  2. ターゲット間で同じ App Group 識別子を使用する
  3. 各ターゲットで共有の `CredentialsManager` を構成する

  <div id="authentication-flow-options-comparison">
    ### 認証フローオプションの比較
  </div>

  | 機能                    | Universal Links | エフェメラルセッション | デフォルト (アラート) |
  | --------------------- | --------------- | ----------- | ------------ |
  | 許可アラート                | 抑制 (リダイレクト確認なし) | なし          | すべてのアラートを表示  |
  | SSO サポート              | あり              | なし          | あり           |
  | Apple Developer アカウント | 必須              | 不要          | 不要           |
  | ユーザーエクスペリエンス          | 最良              | 良好          | 許容レベル        |
  | セットアップの複雑さ            | 中               | 容易          | 容易           |
  | プライベートブラウズのサポート       | あり              | あり          | なし           |

  **推奨事項:**

  * **SSO を利用する本番アプリ**: Universal Links（より良い UX、SSO サポートあり、Apple Developer アカウントが必要）
  * **SSO を利用しない本番アプリ**: エフェメラルセッション（アラートなし、セットアップが簡単）
  * **テスト / 開発用途**: エフェメラルセッション（セットアップが速く、最もクリーンな UX）
  * **クイックスタート / プロトタイピング**: アラート付きデフォルト（セットアップ不要で、後から移行可能）
</Accordion>
