> ## Documentation Index
> Fetch the complete documentation index at: https://auth0-docs-event-stream-action-templates.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Add Login to Your iOS or macOS Application using the Auth0.swift SDK

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

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()) {
              const escapedKey = key.replaceAll(/[.*+?^${}()|[\]\\]/g, (String.raw)`\$&`);
              processedNode = processedNode.replaceAll(new RegExp(escapedKey, "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>;
};

<HowToSchema />

<Accordion title="Use AI to integrate Auth0" icon="microchip-ai" iconType="solid" defaultOpen>
  If you use an AI coding assistant like Claude Code, Cursor, or GitHub Copilot, you can add Auth0 authentication automatically in minutes using [agent skills](https://agentskills.io/home).

  **Install:**

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

  **Then ask your AI assistant:**

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

  Your AI assistant will automatically create your Auth0 application, fetch credentials, add the Auth0.swift SDK dependency, configure Auth0.plist, set up callback URLs, and implement login/logout flows. [Full agent skills documentation →](/docs/quickstart/agent-skills)
</Accordion>

## Get Started

<Steps>
  <Step title="Create a new project" stepNumber={1}>
    Create a new iOS or macOS project for this quickstart.

    **In Xcode:**

    1. **File** → **New** → **Project** (or **⌘+Shift+N**)
    2. Select either:
       * **iOS** tab → **App** template
       * **macOS** tab → **App** template
    3. Configure your project:
       * **Product Name**: `Auth0-Sample`
       * **Interface**: SwiftUI
       * **Language**: Swift
       * **Use Core Data**: Unchecked
       * **Include Tests**: Checked (recommended)
    4. Choose a location and click **Create**

    <Tip>
      This creates a standard app with SwiftUI and Swift Package Manager support, perfect for Auth0 integration.
    </Tip>
  </Step>

  <Step title="Add the Auth0 SDK" stepNumber={2}>
    Add the Auth0 SDK to your project using your preferred package manager.

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

        1. **File** → **Add Package Dependencies...** (or **⌘+Shift+K**)
        2. Enter the Auth0 SDK URL:
           ```
           https://github.com/auth0/Auth0.swift
           ```
        3. **Add Package** → Select your app target → **Add Package**
      </Tab>

      <Tab title="CocoaPods">
        1. Create a `Podfile` in your project directory:
           ```ruby Podfile theme={null}
           platform :ios, '14.0' # Or platform :osx, '11.0' for macOS
           use_frameworks!

           target 'YourApp' do
             pod 'Auth0', '~> 2.0'
           end
           ```
        2. Install the dependencies:
           ```bash theme={null}
           pod install
           ```
        3. Open the generated `.xcworkspace` file (not `.xcodeproj`)
      </Tab>

      <Tab title="Carthage">
        1. Create a `Cartfile` in your project directory:
           ```text Cartfile theme={null}
           github "auth0/Auth0.swift" ~> 2.0
           ```
        2. Run Carthage:
           ```bash theme={null}
           carthage update --platform iOS --use-xcframeworks
           ```
           For macOS, use `--platform macOS`
        3. Drag the generated `Auth0.xcframework` from `Carthage/Build` into your Xcode project
        4. In your target's **General** settings, add `Auth0.xcframework` to **Frameworks, Libraries, and Embedded Content**
      </Tab>
    </Tabs>
  </Step>

  <Step title="Configure Auth0" stepNumber={3}>
    Create a new Auth0 application and configure callback URLs.

    1. Go to [Auth0 Dashboard](https://manage.auth0.com/dashboard/)
    2. **Applications** > **Create Application** > Name it, select **Native** > **Create**
    3. In the **Settings** tab, note your **Client ID** and **Domain**
    4. Add the following URLs to **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. Add the following URLs to **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. Click **Save Changes**
  </Step>

  <Step title="Configure App Credentials" stepNumber={4}>
    Create `Auth0.plist` in your project directory:

    ```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>
    ```

    Drag `Auth0.plist` into Xcode and ensure "Add to target" is checked.
  </Step>

  <Step title="Create the Authentication Service" stepNumber={5}>
    Create `AuthenticationService.swift` to handle login, logout, and token storage.

    <Info>
      **Use `CredentialsManager` for token storage.** The `CredentialsManager` class securely stores credentials in the Keychain and automatically refreshes expired access tokens. Always use it — do not store tokens in memory, `UserDefaults`, or `localStorage`.
    </Info>

    1. Right-click your project → **New File...** → **Swift File**
    2. Name it `AuthenticationService`
    3. Replace contents with:

    ```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
            // Get user info from the ID token
            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
                // Get user info from the ID token
                user = credentials.user
            } catch {
                errorMessage = "Login failed: \(error.localizedDescription)"
            }
        }
        
        func logout() async {
            isLoading = true
            defer { isLoading = false }
            
            do {
                try await Auth0
                  .webAuth()
                  .clearSession()
                _ = credentialsManager.clear()
                isAuthenticated = false
                user = nil
            } catch {
                errorMessage = "Logout failed: \(error.localizedDescription)"
            }
        }
    }
    ```
  </Step>

  <Step title="Configure Authentication Flow (Optional)" stepNumber={6}>
    To improve the user experience, you can minimize system alerts in the following ways:

    1. Use Universal Links: This eliminates the 'Open in "AppName"?' prompt that appears during the redirect. Note: The ASWebAuthenticationSession permission alert will still appear.
    2. Use Ephemeral Sessions: This eliminates all permission alerts. Note: This disables Single Sign-On (SSO) and shared cookies.

    <Tip>
      **Skip this step** to use the default behavior with a permission alert. You can configure this later.
    </Tip>

    <Tabs>
      <Tab title="Universal Links">
        1. Auth0 Dashboard → **Applications** → Your app → **Settings** → **Advanced Settings** → **Device Settings**
        2. Add **Apple Team ID** and **bundle identifier** → **Save**
        3. Xcode: Target → **Signing & Capabilities** → **+ Capability** → **Associated Domains**
        4. Add: `webcredentials:{yourDomain}`

        <Warning>Requires: Paid Apple Developer account, iOS 17.4+/macOS 14.4+</Warning>

        <Tip>
          Best for production apps.
        </Tip>
      </Tab>

      <Tab title="Ephemeral Session">
        Add `.useEphemeralSession()` to the login call in `AuthenticationService.swift`:

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

        <Info>
          When using ephemeral sessions, you don't need to call `clearSession()` on logout. Just clear the credentials from your app - there's no shared cookie to remove.
        </Info>

        <Tip>
          Quick setup, no alerts, but users must log in every time (no SSO).
        </Tip>
      </Tab>
    </Tabs>
  </Step>

  <Step title="Run your app" stepNumber={8}>
    Press **⌘+R** in Xcode.

    1. Tap "Log In" → Permission alert (if using default) → Tap "Continue"
    2. Complete login in browser
    3. See your profile!
  </Step>
</Steps>

<Check>
  **Checkpoint**

  You now have a fully functional Auth0 login in your iOS or macOS app!
</Check>

***

## Troubleshooting & Advanced

<Accordion title="Common Issues & Solutions">
  ### Build errors: 'Auth0' module not found

  **Solutions**:

  1. **Swift Package Manager**: Check **Package Dependencies** → Verify `Auth0.swift` is listed
  2. **CocoaPods**: Ensure you're opening the `.xcworkspace` file, not `.xcodeproj`
  3. **Carthage**: Verify `Auth0.xcframework` is added to **Frameworks, Libraries, and Embedded Content**
  4. Clean and rebuild: **⌘+Shift+K** then **⌘+R**
  5. Restart Xcode if needed

  ### App crashes: 'Auth0.plist not found'

  **Fix**:

  1. Verify `Auth0.plist` is in your Xcode project navigator
  2. Select the file → Inspector → Ensure your app target is checked
  3. Confirm it has `ClientId` and `Domain` keys with your values

  ### Browser opens but never returns to app

  **Fix**:

  1. Check callback URLs in Auth0 Dashboard match your bundle identifier and platform exactly
  2. For iOS: URLs should contain `/ios/`, for macOS: `/macos/`
  3. Verify bundle identifier in Xcode matches Auth0 settings
  4. Ensure no typos in URLs (common: missing colons, wrong domain format)
  5. **Custom domain users**: Verify you're using your custom domain, not the Auth0 domain

  ### Permission alert appears every time

  This is standard iOS/macOS security behavior when using custom URL schemes. See **Step 6** to eliminate this alert using Universal Links or Ephemeral Sessions.
</Accordion>

<Accordion title="Custom Domain Configuration">
  If you're using a [custom domain](/docs/customize/custom-domains), use its value instead of your Auth0 domain everywhere.

  **Example:** Use `login.example.com` instead of `tenant.auth0.com`

  This is **required** for certain features to work properly:

  * Update `Auth0.plist` with your custom domain
  * Use custom domain in callback/logout URLs
  * For Universal Links, use: `webcredentials:login.example.com`
</Accordion>

<Accordion title="Production Deployment">
  ### App Store Preparation

  * Configure Universal Links to eliminate the permission alert
  * Test on multiple platform versions and device sizes
  * Implement proper error handling for network failures
  * Add Privacy Usage descriptions if using Keychain with biometrics
  * Follow App Store Review Guidelines for authentication flows

  ### Security Best Practices

  * Never log sensitive authentication data in production
  * Implement App Transport Security (ATS) compliance
  * Use HTTPS for all network requests
  * **Do NOT** pin Auth0 API certificates - [Auth0 does not recommend this practice](/docs/troubleshoot/product-lifecycle/past-migrations#avoid-pinning-or-fingerprinting-tls-certificates-for-auth0-endpoints)

  ### Performance Optimization

  * All async operations properly use `@MainActor` for UI updates
  * `@Published` properties use proper memory handling
  * Credentials are cached securely in the Keychain for offline access
  * User profile is retrieved from ID token (no additional network request)
</Accordion>

<Accordion title="Advanced Integration">
  ### Enhanced Keychain Security with Biometrics

  Require Face ID or Touch ID to access stored credentials:

  ```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
  }()
  ```

  When enabled, users must authenticate with biometrics before the SDK can retrieve stored credentials.

  ### Automatic Token Refresh

  The `CredentialsManager` automatically refreshes expired access tokens:

  ```swift theme={null}
  // Get credentials - automatically refreshes if expired
  func getAccessToken() async throws -> String {
      let credentials = try await credentialsManager.credentials()
      return credentials.accessToken
  }
  ```

  Use this pattern when making API calls that require an access token.

  ### Shared Credentials Across App Extensions

  For widgets, app extensions, or background tasks that need access tokens:

  ```swift theme={null}
  // Create a shared credentials manager with an app group
  let credentialsManager = CredentialsManager(
      authentication: Auth0.authentication(),
      storeKey: "credentials",
      storage: .shared(withIdentifier: "group.com.example.myapp")
  )
  ```

  **Requirements:**

  1. Enable **App Groups** capability in Xcode for all targets
  2. Use the same app group identifier across targets
  3. Configure the shared `CredentialsManager` in each target

  ### Authentication Flow Options Comparison

  | Feature                  | Universal Links              | Ephemeral Session | Default (Alert)  |
  | ------------------------ | ---------------------------- | ----------------- | ---------------- |
  | Permission Alert         | Reduced (no redirect prompt) | None              | Shows all alerts |
  | SSO Support              | Yes                          | No                | Yes              |
  | Apple Developer Account  | Required                     | Not required      | Not required     |
  | User Experience          | Best                         | Good              | Acceptable       |
  | Setup Complexity         | Medium                       | Easy              | Easy             |
  | Private Browsing Support | Yes                          | Yes               | No               |

  **Recommendations:**

  * **Production apps with SSO**: Universal Links (better UX, SSO support, requires Apple Developer account)
  * **Production apps without SSO**: Ephemeral Sessions (no alerts, simpler setup)
  * **Testing/Development**: Ephemeral Sessions (quick setup, cleanest UX)
  * **Quick start/Prototyping**: Default with alerts (no setup, can migrate later)
</Accordion>
