Skip to main content

Get Started

1

Create a new iOS project

Create a new iOS project for this quickstart.In Xcode:
  1. FileNewProject (or ⌘+Shift+N)
  2. Select iOS tab → App template
  3. Configure your project:
    • Product Name: Auth0-iOS-Sample
    • Interface: SwiftUI
    • Language: Swift
    • Use Core Data: Unchecked
    • Include Tests: Checked (recommended)
  4. Choose a location and click Create
This creates a standard iOS app with SwiftUI and Swift Package Manager support, perfect for Auth0 integration.
2

Add Auth0 SDK via Swift Package Manager

Add the Auth0 iOS SDK to your project using Swift Package Manager.In Xcode:
  1. FileAdd Package Dependencies… (or ⌘+Shift+K)
  2. Enter the Auth0 iOS SDK URL:
    https://github.com/auth0/Auth0.swift
    
  3. Add Package → Select your app target → Add Package
Package details:
  • Auth0.swift: Main authentication SDK
  • JWTDecode: JWT token parsing utilities
  • SimpleKeychain: Secure iOS Keychain wrapper
Swift Package Manager automatically handles dependency resolution and updates. The Auth0 SDK will appear in your Project Navigator under Package Dependencies.
3

Setup your Auth0 App

Next up, you need to:
  1. Create a new Native Application on your Auth0 tenant
  2. Configure your iOS app with Auth0 credentials
  3. Add the Auth0 configuration file to your Xcode project

Create Auth0 Application

  1. Go to the Auth0 Dashboard
  2. Click ApplicationsCreate Application
  3. Name your application (e.g., “My iOS App”)
  4. Choose Native as the application type
  5. Click Create

Configure Application Settings

In your Auth0 application settings:
  1. Go to the Settings tab
  2. Scroll down to Application URIs
  3. In Allowed Callback URLs, add both URLs below (replace placeholders):
    https://YOUR_AUTH0_DOMAIN/ios/YOUR_BUNDLE_IDENTIFIER/callback,
    YOUR_BUNDLE_IDENTIFIER://YOUR_AUTH0_DOMAIN/ios/YOUR_BUNDLE_IDENTIFIER/callback
    
  4. In Allowed Logout URLs, add the same URLs as above
  5. Click Save Changes
Example URLs:
https://dev-abc123.us.auth0.com/ios/com.example.MyApp/callback,
com.example.MyApp://dev-abc123.us.auth0.com/ios/com.example.MyApp/callback

Create Auth0.plist Configuration

Create a configuration file in your project directory (same level as your .xcodeproj file) called Auth0.plist:
Auth0.plist
<?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>YOUR_AUTH0_DOMAIN</string>
</dict>
</plist>
Replace YOUR_AUTH0_CLIENT_ID and YOUR_AUTH0_DOMAIN with the actual values from your Auth0 application’s Settings tab.

Add Auth0.plist to Xcode Project

  1. Drag and drop: In Finder, drag the Auth0.plist file into your Xcode project navigator
  2. Configure import: In the dialog that appears:
    • ✅ Check “Add to target” for your app target
    • ✅ Check “Copy items if needed”
    • Click Finish
  3. Verify: The file should now appear in your Xcode project navigator
Important: The plist file must be added to your app target, not just the project. If authentication fails, verify the plist file is included in your target.
4

Create the Authentication Service

Create a centralized service to handle all authentication logic.Add a new Swift file:
  1. Right-click your project group → New File…Swift File
  2. Name it AuthenticationService
  3. Replace its contents with:
AuthenticationService.swift
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() {
        checkAuthenticationStatus()
    }
    
    private func checkAuthenticationStatus() {
        isLoading = true
        credentialsManager.credentials { result in
            DispatchQueue.main.async {
                self.isLoading = false
                switch result {
                case .success(let credentials):
                    self.isAuthenticated = true
                    self.fetchUserInfo(with: credentials.accessToken)
                case .failure:
                    self.isAuthenticated = false
                }
            }
        }
    }
    
    func login() {
        isLoading = true
        errorMessage = nil
        
        Auth0.webAuth()
            .scope("openid profile email offline_access")
            .start { result in
                DispatchQueue.main.async {
                    self.isLoading = false
                    switch result {
                    case .success(let credentials):
                        _ = self.credentialsManager.store(credentials: credentials)
                        self.isAuthenticated = true
                        self.fetchUserInfo(with: credentials.accessToken)
                    case .failure(let error):
                        self.errorMessage = "Login failed: \(error.localizedDescription)"
                    }
                }
            }
    }
    
    func logout() {
        isLoading = true
        Auth0.webAuth()
            .clearSession { result in
                DispatchQueue.main.async {
                    self.isLoading = false
                    switch result {
                    case .success:
                        _ = self.credentialsManager.clear()
                        self.isAuthenticated = false
                        self.user = nil
                    case .failure(let error):
                        self.errorMessage = "Logout failed: \(error.localizedDescription)"
                    }
                }
            }
    }
    
    private func fetchUserInfo(with accessToken: String) {
        Auth0.authentication()
            .userInfo(withAccessToken: accessToken)
            .start { result in
                DispatchQueue.main.async {
                    if case .success(let userInfo) = result {
                        self.user = userInfo
                    }
                }
            }
    }
}
5

Create Login, Logout and Profile Components

Create the UI components that respond to authentication state.Create files
touch AuthenticatedView.swift && touch UnauthenticatedView.swift && touch ProfileCard.swift && touch LoadingView.swift
And add the following code snippets
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 iOS Sample")
                .font(.largeTitle)
                .fontWeight(.bold)
            
            if authService.isLoading {
                LoadingView()
            } else if authService.isAuthenticated {
                AuthenticatedView(authService: authService)
            } else {
                UnauthenticatedView(authService: authService)
            }
            
            Spacer()
        }
        .padding()
        .alert("Error", isPresented: .constant(authService.errorMessage != nil)) {
            Button("OK") { authService.errorMessage = nil }
        } message: {
            Text(authService.errorMessage ?? "")
        }
    }
}
6

Configure Associated Domains (Optional)

Skip this step if you’re just getting started. This is for production apps with paid Apple Developer accounts.
7

Run your app

# In Xcode, press Cmd+R or click the Run button
Expected flow:
  1. App launches with “Log In” button
  2. Tap “Log In” → iOS permission alert → Tap “Continue”
  3. Safari opens → Complete login → Returns to app
  4. Success! See your profile information
iOS will show a permission alert for your Auth0 domain. This is normal security behavior - tap Continue.
CheckpointYou should now have a fully functional Auth0 login page running on your iOS simulator or device

Next up:

Secure your API

Integrate the Auth0 SDK on your backend service to authenticate API calls

Build MFA

Go beyond basic authentication and learn how to enable MFA

Troubleshooting & Advanced

Build errors: ‘Auth0’ module not found

Solutions:
  1. Check Package Dependencies → Verify Auth0.swift is listed
  2. Clean and rebuild: ⌘+Shift+K then ⌘+R
  3. 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

Safari opens but never returns to app

Fix:
  1. Check callback URLs in Auth0 Dashboard match your bundle identifier exactly
  2. Verify bundle identifier in Xcode matches Auth0 settings
  3. Ensure no typos in URLs (common: missing colons, wrong domain format)

Permission alert appears every time

This is normal iOS security behavior. Consider Universal Links (Step 6) for production apps.

App Store Preparation

  • Configure Associated Domains for Universal Links
  • Test on multiple iOS versions and device sizes
  • Implement proper error handling for network failures
  • Add Privacy Usage descriptions for Keychain access
  • Follow App Store Review Guidelines for authentication flows

Security Considerations

  • Never log sensitive authentication data in production
  • Use Certificate Pinning for additional API security
  • Implement App Transport Security (ATS) compliance
  • Consider DeviceCheck for fraud prevention

Performance Optimization

  • All Auth0 callbacks are dispatched to main queue appropriately
  • @Published properties use proper memory handling
  • App handles authentication state during background/foreground transitions

Enhanced Keychain Security

Implement biometric authentication for credential access:
private let credentialsManager: CredentialsManager = {
    let manager = CredentialsManager(authentication: Auth0.authentication())
    manager.enableBiometrics(withTitle: "Unlock with Face ID", 
                           cancelTitle: "Cancel", 
                           fallbackTitle: "Use Passcode",
                           evaluationPolicy: .deviceOwnerAuthenticationWithBiometrics)
    return manager
}()

App Lifecycle Integration

Handle authentication state during app lifecycle transitions:
@main
struct Auth0_iOS_SampleApp: App {
    @Environment(\.scenePhase) private var scenePhase
    @StateObject private var authService = AuthenticationService()
    
    var body: some Scene {
        WindowGroup {
            ContentView()
                .environmentObject(authService)
                .onChange(of: scenePhase) { newPhase in
                    if newPhase == .active {
                        authService.refreshTokenIfNeeded()
                    }
                }
        }
    }
}

Token Refresh

Automatically refresh expired tokens:
func refreshTokenIfNeeded() {
    credentialsManager.credentials { result in
        DispatchQueue.main.async {
            switch result {
            case .success(let credentials):
                self.credentials = credentials
            case .failure(let error):
                if case .noCredentials = error {
                    self.isAuthenticated = false
                }
            }
        }
    }
}