This document provides context and guidelines for AI coding assistants working with the Auth0.swift codebase.
Auth0.swift is the official Auth0 SDK for Apple platforms — providing authentication, authorization, and credential management for iOS, macOS, tvOS, watchOS, and visionOS apps.
- Language: Swift 5.0+ (Package.swift uses Swift 6.0 tools)
- Tech Stack: Apple platforms, Xcode 16.x, SPM + CocoaPods + Carthage, URLSession, Combine, CryptoKit
- Package Manager: Swift Package Manager (primary), CocoaPods, Carthage (development deps)
- Minimum Platform Versions: iOS 14.0, macOS 11.0, tvOS 14.0, watchOS 7.0, visionOS 1.0
Copy-paste ready. These are the exact commands used in CI.
# Run all tests via Swift Package Manager (fastest local option)
swift test
# Run tests for a specific Xcode scheme (used in CI)
xcodebuild test -project Auth0.xcodeproj -scheme Auth0.iOS -destination 'platform=iOS Simulator,name=iPhone 16'
xcodebuild test -project Auth0.xcodeproj -scheme Auth0.macOS -destination 'platform=macOS'
xcodebuild test -project Auth0.xcodeproj -scheme Auth0.tvOS -destination 'platform=tvOS Simulator,name=Apple TV'
# Lint (must pass before merging)
swiftlint lint --reporter github-actions-logging
# Lint with auto-fix
swiftlint lint --fix
# Bootstrap Carthage dependencies (required for Xcode project development)
carthage bootstrap --use-xcframeworks
# Bootstrap Carthage for a specific platform
carthage bootstrap --platform iOS --use-xcframeworks --no-use-binaries --cache-builds
# Coverage report (iOS only, run after tests)
bundle exec slather coverage -x --scheme Auth0.iOS Auth0.xcodeproj
# Validate CocoaPods spec
bundle exec pod lib lint --allow-warnings --fail-fast
# Resolve SPM dependencies
xcodebuild -resolvePackageDependencies -skipPackageUpdates -onlyUsePackageVersionsFromResolvedFile
# Generate API documentation (DocC via Fastlane)
bundle exec fastlane build_docs- Framework: Quick 7.0+ (BDD) + Nimble 13.0+ (assertions)
- Test Location:
Auth0Tests/ - Coverage Tool: Slather + Codecov (iOS scheme only in CI)
- Coverage Threshold: Tracked via Codecov; target >80%
# Run all unit tests via SPM (quickest)
swift test
# Run a specific test spec via xcodebuild
xcodebuild test -project Auth0.xcodeproj \
-scheme Auth0.iOS \
-destination 'platform=iOS Simulator,name=iPhone 16' \
-only-testing:Auth0Tests/CredentialsManagerSpec- Every spec file is a
QuickSpecsubclass named<Subject>Spec(e.g.,CredentialsManagerSpec). - Behavior is organized with nested
describe/context/itblocks. itdescriptions use present tense, declarative style:"should return credentials when valid".beforeEach/afterEachhandle setup and teardown.StubURLProtocolintercepts all network calls — never make real network requests in tests.NetworkStub.clearStubs()must be called in everyafterEach.- Test constants use
UPPER_CAMEL_CASEnames (e.g.,AccessToken,ClientId,Domain). - Combine publishers are tested with Nimble async matchers or
waitUntil. - Platform-specific tests are gated with
#if WEB_AUTH_PLATFORMand#if PASSKEYS_PLATFORM.
- Network:
StubURLProtocol+NetworkStub(register/clear stubs per test) - Keychain:
SimpleKeychainis used directly; tests clean up Keychain state inafterEach - Platform guards: tests mirror the same
#if WEB_AUTH_PLATFORM/#if PASSKEYS_PLATFORMflags as source
Auth0.swift/
├── Auth0/ # Library source (85 Swift files)
│ ├── Auth0.swift # Public result type aliases & top-level factory functions
│ ├── Authentication.swift # Authentication protocol (OAuth2 / OIDC)
│ ├── Auth0Authentication.swift # Concrete Authentication implementation
│ ├── AuthenticationError.swift # Authentication API error type
│ ├── CredentialsManager.swift # Thread-safe Keychain credential storage & renewal
│ ├── CredentialsManagerError.swift
│ ├── Credentials.swift # User credentials model
│ ├── WebAuth.swift # Web Auth protocol (Universal Login)
│ ├── Auth0WebAuth.swift # Concrete WebAuth implementation
│ ├── WebAuthError.swift
│ ├── Version.swift # Single source of truth for SDK version string
│ ├── DPoP/ # DPoP (Demonstration of Proof-of-Possession) support
│ │ ├── DPoP.swift
│ │ └── DPoPError.swift
│ ├── MFA/ # Multi-factor authentication
│ │ ├── MFAClient.swift
│ │ ├── Auth0MFAClient.swift
│ │ └── MFAErrors.swift
│ ├── MyAccount/ # My Account API
│ │ ├── MyAccount.swift
│ │ ├── MyAccountError.swift
│ │ └── AuthenticationMethods/
│ └── Utils/ # Internal utilities
├── Auth0Tests/ # Test specs (56 files, mirrors Auth0/ structure)
│ ├── Auth0Spec.swift
│ ├── AuthenticationSpec.swift
│ ├── CredentialsManagerSpec.swift
│ ├── DPoP/
│ ├── MFA/
│ └── MyAccount/
├── Documentation.docc/ # DocC documentation bundle
├── App/ # Demo application
├── fastlane/ # Release automation (Fastfile)
├── .github/
│ ├── workflows/
│ │ ├── main.yml # CI: tests, lint, pod-lint
│ │ ├── claude-code-review.yml
│ │ ├── sca_scan.yml
│ │ └── rl-scanner.yml
│ └── actions/
│ ├── setup/ # Composite: Ruby + CocoaPods + Xcode setup
│ └── test/ # Composite: Carthage bootstrap + xcodebuild
├── Auth0.xcodeproj
├── Auth0.podspec
├── Package.swift
├── Cartfile / Cartfile.resolved
└── CHANGELOG.md
| File | Purpose |
|---|---|
Auth0/Auth0.swift |
Entry point: result type aliases and factory functions (Auth0.authentication(), Auth0.webAuth(), etc.) |
Auth0/Version.swift |
Version string — single source of truth; bump here for every release |
Auth0/CredentialsManager.swift |
Thread-safe credential storage, renewal, biometric auth |
Auth0/Authentication.swift |
Full OAuth2/OIDC Authentication protocol definition |
Auth0/WebAuth.swift |
Universal Login protocol (iOS/macOS/visionOS only, WEB_AUTH_PLATFORM) |
Auth0.podspec |
CocoaPods spec; s.version must match Version.swift |
Package.swift |
SPM manifest; lists all targets, platforms, and dependencies |
.swiftlint.yml |
SwiftLint config — lints only the Auth0/ source directory |
CHANGELOG.md |
Keep a Changelog format; updated for every release |
- Linter: SwiftLint — Config:
.swiftlint.yml- Opt-in rules:
empty_count - Disabled rules:
void_function_in_ternary,large_tuple,blanket_disable_command - Line length: 500 (not the primary style enforcement)
- Type body length: 300 warning / 400 error
- Opt-in rules:
- Formatter: No auto-formatter enforced; 4-space indentation, no tabs
- Types (classes, structs, protocols, enums):
PascalCase— e.g.,CredentialsManager,AuthenticationError,WebAuthError - Functions and properties:
camelCase— e.g.,accessToken,renewCredentials,enableBiometrics - Constants in test files:
UpperCamelCase(private let at file scope) — e.g.,AccessToken,ClientId,Domain - Protocol-backed implementations are prefixed with
Auth0:Auth0Authentication,Auth0WebAuth,Auth0MFAClient - Error types end in
Error:AuthenticationError,WebAuthError,CredentialsManagerError
// Only iOS, macOS, macCatalyst, visionOS — never use #if os(iOS) for SDK-level WebAuth guards
#if WEB_AUTH_PLATFORM
// Only iOS, macOS, macCatalyst, visionOS (Passkeys)
#if PASSKEYS_PLATFORM✅ Good — typed Result, dual async/callback API, no force-unwrap:
public func credentials(withScope scope: String? = nil,
minTTL: Int = 0,
parameters: [String: Any] = [:],
headers: [String: String] = [:]) async throws -> Credentials {
return try await withCheckedThrowingContinuation { continuation in
self.credentials(withScope: scope, minTTL: minTTL, parameters: parameters, headers: headers) {
continuation.resume(with: $0)
}
}
}❌ Bad — stringly-typed error, force-unwrap, untyped completion:
func getCredentials(completion: @escaping (Any?, Error?) -> Void) {
let creds = storage.getCredentials()! // force-unwrap
completion(creds, nil)
}- Protocol + concrete implementation: Every public API is a protocol (
Authentication,WebAuth,MFAClient); the concrete type is package-internal (Auth0Authentication,Auth0WebAuth). - Builder pattern:
WebAuthuses a fluent builder —webAuth.scope("openid").connection("google-oauth2").start(). - Result type aliases: Each subsystem has a typed result alias —
AuthenticationResult<T>,WebAuthResult<T>,CredentialsManagerResult<T>,MyAccountResult<T>. - Dual API (callback + async/await): Every public method exposes both a completion handler variant and a Swift concurrency (
async throws) variant. - Sendable / thread safety:
CredentialsManagerisSendable; concurrent methods useNSLockinternally. Document thread-safety limits in DocC comments.
No enforced convention; use descriptive names: feature/dpop-support, fix/credentials-renewal-race, chore/bump-dependencies.
Free-form with conventional-style prefixes used in practice:
feat: add flexible grant type support
fix: correct memory leak in ASUserAgent
chore: deprecate Management API client
docs: update Native to Web feature docs for GA release
Use .github/PULL_REQUEST_TEMPLATE.md:
- All new/changed/fixed functionality must be covered by tests.
- All new/changed public API must have DocC comments.
- Required CI checks: unit tests on iOS + macOS + tvOS, SwiftLint, pod lib lint, Swift package tests.
- Sections: Changes (types/methods added/deleted/deprecated/changed), References (GitHub issues, community posts), Testing (how reviewers can verify).
Keep a Changelog format. Update CHANGELOG.md for every user-facing change under the correct heading: Added, Changed, Deprecated, Fixed, Security, Removed.
- Write or update tests in
Auth0Tests/for every new or changed behavior. - Add DocC comments (
/// ...) to allpublictypes, methods, and properties. - Update
CHANGELOG.mdfor every user-facing addition, change, fix, deprecation, or security update. - Gate WebAuth and Passkeys code with
#if WEB_AUTH_PLATFORM/#if PASSKEYS_PLATFORM. - Expose both a completion-handler API and an
async throwsAPI for any new public method. - Keep
Auth0/Version.swiftandAuth0.podspecs.versionin sync. - Follow the existing error hierarchy — use or extend typed error structs (
AuthenticationError,WebAuthError, etc.). - Run
swiftlint lintand resolve all warnings before submitting. - Use
StubURLProtocol/NetworkStubfor all network interactions in tests.
- Adding new external dependencies (SPM packages or CocoaPods pods).
- Modifying public API signatures — breaking changes require a major version bump.
- Adding new minimum platform versions or dropping support for existing ones.
- Changes to
.github/workflows/CI configuration. - Modifying security-sensitive code: DPoP key generation, PKCE, token storage, biometric auth.
- Deprecating or removing any public API.
- Changes to
Package.swifttarget structure (adding targets, changing paths, new compilation conditions).
- Commit secrets, API keys, tokens, or
.plistfiles containing real credentials. - Log
accessToken,refreshToken,idToken, or any sensitive user data — not in source, not in tests. - Disable PKCE — it is always enabled for Authorization Code flows.
- Bypass or weaken DPoP proof generation.
- Force-unwrap optionals in library source code.
- Use
#if os(iOS)/#if os(macOS)for guards that belong underWEB_AUTH_PLATFORM/PASSKEYS_PLATFORM. - Modify files under
Carthage/,Pods/,.build/, ordocs/(generated artifacts) by hand. - Remove or skip failing tests instead of fixing them.
- Break backward API compatibility without a major version bump and explicit team approval.
- Write
publictypes or methods without DocC documentation comments.
- PKCE: Always enabled for Authorization Code flows — never provide an option to disable it.
- Token Storage: Keychain via
SimpleKeychain— neverUserDefaults,NSCache, or in-memory-only storage for sensitive tokens. - Token Logging: Never log
accessToken,refreshToken,idToken, orrecoveryCode— not even in debug builds. - DPoP: Supported — keys generated in the Secure Enclave where available. Do not silently downgrade to software keys.
- Certificate Pinning: Not built-in; can be configured via a custom
URLSessionpassed at init. - Biometric Auth: Optional gate on
CredentialsManager.credentials()viaLocalAuthentication— never store biometric data.
| Package | Version | Purpose |
|---|---|---|
SimpleKeychain |
1.3.0 | Keychain access abstraction |
JWTDecode.swift |
3.3.0 | ID token parsing and validation |
| Package | Version | Purpose |
|---|---|---|
Quick |
7.0.0+ | BDD test framework |
Nimble |
13.0.0+ | Assertion matchers |
| Tool | Purpose |
|---|---|
| Carthage | Resolves test/dev dependencies for the Xcode project |
| SwiftLint | Static analysis |
| Slather | Coverage report generation |
| Bundler | Manages Ruby tools (CocoaPods, Fastlane, Slather) |
| Fastlane | Release automation and DocC generation |
- Bump version in
Auth0/Version.swift— single source of truth. - Update
Auth0.podspecs.versionto match. - Update
CHANGELOG.md— add release heading with date and full change list. - Open a PR, get review, merge to
master. - Tag the release:
git tag <version> && git push --tags. - Run Fastlane release lane:
bundle exec fastlane release— tags, pushes podspec to CocoaPods trunk. - The
rl-scannerCI job scans the release artifact automatically on release PRs.
- Missing conditional compilation flag:
WebAuthand Passkeys types only exist onWEB_AUTH_PLATFORM. Forgetting#if WEB_AUTH_PLATFORMcauses tvOS/watchOS build failures. - Carthage vs SPM for development: The Xcode project uses Carthage-built
.xcframeworks. Runcarthage bootstrap --use-xcframeworksbefore opening the project in Xcode; SPM is only used forswift testin CI. - Thread safety of CredentialsManager: Only
credentials(),apiCredentials(),ssoCredentials(), andrenew()are thread-safe. Accessing non-thread-safe properties (e.g.,bioAuth) from concurrent contexts requires external synchronization. - Swift 6 concurrency:
Package.swiftuses Swift language mode v5 butswift-tools-version:6.0. Adding newSendableconformances requires understanding the existing lock-based concurrency model — check@unchecked Sendableusages first. - Nimble async matchers: Use
await expect(value).to(...)— notexpect(value).toEventually(...)with a synchronous expectation, which produces flaky tests under Swift concurrency.