## Use AI to integrate Auth0

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:**

```
npx skills add auth0/agent-skills --skill auth0
```

**Then ask your AI assistant:**

```
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 →](/content/docs/quickstart/agent-skills/index.html)

## Get Started

1. **Create a new project**  
   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**

This creates a standard app with SwiftUI and Swift Package Manager support, perfect for Auth0 integration.

2. **Add the Auth0 SDK**  
   Add the Auth0 SDK to your project using your preferred package manager.
   - Swift Package Manager
   - CocoaPods
   - Carthage

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

1. Create a `Podfile` in your project directory:
   
   ```
   platform :ios, '14.0' # Or platform :osx, '11.0' for macOS
   use_frameworks!

target 'YourApp' do
        pod 'Auth0', '~> 3.0'
   end
   ```

2. Install the dependencies:
   
   ```
   pod install
   ```

3. Open the generated `.xcworkspace` file (not `.xcodeproj`)

1. Create a `Cartfile` in your project directory:
   
   ```
   github "auth0/Auth0.swift" ~> 3.0
   ```

2. Run Carthage:
   
   ```
   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**

3. **Configure Auth0**  
   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**:

- iOS
   - macOS

```
   https://{yourDomain}/ios/YOUR_BUNDLE_IDENTIFIER/callback,
   YOUR_BUNDLE_IDENTIFIER://{yourDomain}/ios/YOUR_BUNDLE_IDENTIFIER/callback
   ```
   ```
   https://{yourDomain}/macos/YOUR_BUNDLE_IDENTIFIER/callback,
   YOUR_BUNDLE_IDENTIFIER://{yourDomain}/macos/YOUR_BUNDLE_IDENTIFIER/callback
   ```

5. Add the following URLs to **Allowed Logout URLs**:

- iOS
   - macOS

6. Click **Save Changes**

4. **Configure App Credentials**  
   Create `Auth0.plist` in your project directory:
   
   ```
   <?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>
   ```

Never hardcode `clientId` or `domain` values directly in Swift source files — they will be committed to version control. Read them from environment variables or a build-time configuration file at runtime. For most apps, prefer `Auth0.plist` (the default approach in this quickstart).

Drag `Auth0.plist` into Xcode and ensure “Add to target” is checked.

5. **Create the Authentication Service**  
   Create `AuthenticationService.swift` to handle login, logout, and token storage.

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

1. Right-click your project → **New File…** → **Swift File**
   2. Name it `AuthenticationService`
   3. Replace contents with:
   
   ```swift
   import Foundation
   import Auth0
   import Combine

@MainActor
   class AuthenticationService: ObservableObject {
       @Published var isAuthenticated = false
       @Published var user: UserProfile?
       @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 the user profile from the stored ID token
           user = try? credentialsManager.userProfile()
       }

func login() async {
           isLoading = true
           errorMessage = nil
           defer { isLoading = false }

do {
               // offline_access is included in the default scope as of v3, shown here for clarity
               _ = try await Auth0
                   .webAuth()
                   .scope("openid profile email offline_access")
                   .useCredentialsManager(credentialsManager)
                   .start()

isAuthenticated = true
               // Get the user profile from the stored ID token
               user = try? credentialsManager.userProfile()
           } catch {
               errorMessage = "Login failed: \(error.localizedDescription)"
           }
       }

func logout() async {
           isLoading = true
           defer { isLoading = false }

do {
               try await Auth0
                 .webAuth()
                 .useCredentialsManager(credentialsManager)
                 .logout()
               isAuthenticated = false
               user = nil
           } catch {
               errorMessage = "Logout failed: \(error.localizedDescription)"
           }
       }
   }
   ```

See all 70 lines

6. **Configure Authentication Flow (Optional)**  
   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.

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

- Universal Links
   - Ephemeral Session

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

Requires: Paid Apple Developer account, iOS 17.4+/macOS 14.4+
   
   Best for production apps.

Add `.useEphemeralSession()` to the login call in `AuthenticationService.swift`:
   
   ```swift
   // In the login() function
   let credentials = try await Auth0
       .webAuth()
       .scope("openid profile email offline_access")
       .useCredentialsManager(credentialsManager)
       .useEphemeralSession()
       .start()
   ```

When using ephemeral sessions, you don’t need to call `logout()` on the Web Auth client. Just clear the credentials from your app - there’s no shared cookie to remove.

7. **Run your app**  
   Press **⌘+R** in Xcode.
   1. Tap “Log In” → Permission alert (if using default) → Tap “Continue”
   2. Complete login in browser
   3. See your profile!

**Checkpoint**You now have a fully functional Auth0 login in your iOS or macOS app!

## Troubleshooting & Advanced  
### 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.

### Custom Domain Configuration
If you’re using a [custom domain](/content/docs/customize/custom-domains/index.html), 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`

### 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](/content/docs/troubleshoot/product-lifecycle/past-migrations#avoid-pinning-or-fingerprinting-tls-certificates-for-auth0-endpoints/index.html)

#### 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)

### Advanced Integration
#### Enhanced Keychain Security with Biometrics
Require Face ID or Touch ID to access stored credentials:

```swift
private let credentialsManager: CredentialsManager = {
    var 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
// 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
// Create a shared credentials manager with an app group
let credentialsManager = CredentialsManager(
    authentication: Auth0.authentication(),
    storeKey: "credentials",
    storage: SimpleKeychain(accessGroup: "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)
