Auth0.swift SDK
repository·master·Indexed 19 days ago
https://github.com/auth0/auth0.swiftOfficial Swift SDK for integrating Auth0 authentication into iOS and macOS applications. It provides high-level abstractions for Web Authentication (login/logout), a Credentials Manager for secure token storage in the Keychain, and direct API clients for Authentication and Multi-Factor Authentication (MFA).
What's inside Auth0.swift
- Auth0.swift is the official Swift SDK for integrating Auth0 authentication into iOS and macOS applications. It provides high-level abstractions for Web Authentication (login/logout), a Credentials Manager for storing tokens, and direct API clients for Authentication and Multi-Factor Authentication (MFA).
Overview of the Auth0 Swift SDK components
masterThe Auth0 Swift SDK is a collection of modules designed for Apple platforms to handle various authentication tasks. It is composed of four primary components:
- WebAuth: A web-based authentication client used for performing logins and logouts via a secure web view.
- CredentialsManager: A utility for securely storing and retrieving user credentials from the iOS/macOS Keychain.
- Authentication: A client specifically for interacting with the Auth0 Authentication API.
- MyAccount: A client for interacting with the Auth0 My Account API.
What is DocsVersions and how does it work?
masterDocsVersions is a dependency-free Swift tool designed to organize DocC static sites into a versioned GitHub Pages layout.
Because DocC renders navigation as a client-side Vue app, DocsVersions does not rewrite HTML at build time. Instead, it injects a runtime script (
version-selector.js) into every page. This script adds a version-switcher dropdown to the UI by reading a sharedversions.jsonfile.Key features include:
- Automatic Versioning: Reads versions from
Auth0/Version.swiftor a provided flag. - Retention Policy: Implements a 'keep-two-major-lines' policy to ensure the latest major release and the previous major's latest stable release remain available.
- Root Mirroring: For stable releases, it mirrors the content at the site root so the canonical, version-less URL always serves the latest stable documentation.
- Zero Dependencies: It uses only minimal SemVer requirements, making it portable.
- Automatic Versioning: Reads versions from
Identify MFA requirements in Authentication flows
masterWhen handling errors from the
Auth0.authentication()flow (rather than the MFA client), use the following properties onAuthenticationErrorto identify MFA scenarios:isMultifactorRequired: MFA is required to authenticate.isMultifactorEnrollRequired: MFA is required and the user is not yet enrolled.isMultifactorCodeInvalid: The MFA code sent is invalid or expired (legacy).isMultifactorTokenInvalid: The MFA token is invalid or expired (legacy).
Warning: Do not rely on parsing error message strings. Always use the
codeproperty or the boolean flags provided by the API.Auth0.authentication() .login(usernameOrEmail: "user@example.com", password: "password", realmOrConnection: "Username-Password-Authentication") .start { result in switch result { case .success(let credentials): print("Success: \(credentials)") case .failure(let error) where error.isMultifactorRequired: print("MFA is required") // Proceed with MFA flow using extracted token case .failure(let error): print("Failed with: \(error)") } }Use the My Account API to manage user accounts
masterThe My Account API (currently in Early Access) allows you to manage the current user's account, including enrolling and deleting authentication methods.
Important Requirements:
- You must have an access token issued specifically for the My Account API.
- The token must include the necessary scopes for the operations you intend to perform (e.g.,
create:me:authentication_methods,read:me:factors). - Contact Auth0 support to enable this API for your tenant.
Understand the architectural patterns in Auth0.swift
masterThe Auth0.swift SDK follows several consistent design patterns that you should be aware of when extending or interacting with the library:
- Protocol-based API: Every public API is defined as a protocol (e.g.,
Authentication,WebAuth,MFAClient). The concrete implementations (e.g.,Auth0Authentication,Auth0WebAuth) are package-internal. - Dual API (Callback + Async/Await): Every public method provides two ways to call it: a completion handler variant and a Swift concurrency (
async throws) variant. - Builder Pattern: The
WebAuthAPI uses a fluent builder pattern for configuration, such aswebAuth.scope("openid").connection("google-oauth2").start(). - Typed Result Aliases: Each subsystem uses specific typed result aliases, such as
AuthenticationResult<T>,WebAuthResult<T>,CredentialsManagerResult<T>, andMyAccountResult<T>. - Thread Safety: Components like
CredentialsManagerareSendableand useNSLockinternally to ensure thread safety during concurrent operations.
- Protocol-based API: Every public API is defined as a protocol (e.g.,
Swift 6 Concurrency changes in v3
masterTo support Swift 6, Auth0.swift v3 has introduced several concurrency-related changes:
- WebAuth Sendability:
WebAuthand its associated typealiases now conform toSendable. - Main Thread Delivery: Results from Web Auth (callbacks, Combine, and async/await) are guaranteed to be delivered on the
@MainActor. You no longer need to wrap result handling inDispatchQueue.main.async. - JWTDecode Upgrade: The underlying
JWTDecode.swiftdependency has been upgraded to v4.0.0.
- WebAuth Sendability:
Read the `act` claim from the ID token
masterWhen a token exchange involves an actor token, Auth0 may include an
act(actor) claim in the resulting ID token. This claim identifies the acting party and can represent a delegation chain. Theactclaim is exposed via theUserInfotype through theActClaimclass.To read it, you may need to decode the ID token (e.g., using
JWTDecode.swift) and map it toUserInfo:sub: The subject identifier of the acting party.act: A nestedActClaimfor delegation chains.additionalClaims: Extra claims (e.g.,org,role).
You can also access it directly from the
CredentialsManagerviacredentialsManager.user?.act.import JWTDecode let jwt = try decode(jwt: credentials.idToken) let userInfo = UserInfo(json: jwt.body) if let act = userInfo?.act { print("Actor: \(act.sub)") print("Additional claims: \(act.additionalClaims)") // Check for delegation chain if let innerAct = act.act { print("Original actor: \(innerAct.sub)") } }Handle main thread result delivery in v3
masterIn v3, all API variants (Callback, Combine, and Async/await) guarantee that results are delivered on the main thread.
Impact:
- You no longer need
DispatchQueue.main.asyncor.receive(on: DispatchQueue.main)when consuming results for UI updates. - If you need to perform CPU-intensive work with the results, you must explicitly dispatch to a background queue.
Affected APIs:
- All Authentication API methods
- All Credentials Manager methods
- All Web Auth methods
- All My Account API methods
// v3 - already on main thread credentialsManager.credentials { result in self.updateUI(result) } // v3 - dispatch to background for CPU-intensive work credentialsManager.credentials { result in DispatchQueue.global().async { let processed = self.performExpensiveOperation(result) DispatchQueue.main.async { self.updateUI(processed) } } }- You no longer need
Handle IPSIE session expiry [Early Access]
masterWhen using enterprise connections (OIDC/Okta) with session-expiry enforcement enabled, Auth0 emits a
session_expiryclaim.CredentialsManagerautomatically enforces this ceiling. If the ceiling is reached, methods likecredentials(),ssoCredentials(), andapiCredentials()will clear the stored credentials and returnCredentialsManagerError.sessionExpired(with a 30-second clock-skew leeway) instead of attempting renewal.credentialsManager.credentials { result in switch result { case .success(let credentials): print("Obtained credentials: \(credentials)") case .failure(CredentialsManagerError.sessionExpired): // Upstream IdP session ended — prompt re-login case .failure(let error): print("Failed with: \(error)") } }How to test Combine publishers and async code
masterWhen testing asynchronous code or Combine publishers, avoid using
expect(value).toEventually(...)with synchronous expectations, as this causes flakiness in Swift concurrency.Instead, use Nimble's async matchers with the
awaitkeyword:await expect(value).to(...)// Correct way to test async values await expect(value).to(equal(expectedValue))Automatic token redaction in logs
masterTo protect user credentials, Auth0.swift automatically redacts sensitive information from logs. When logging HTTP responses, the following fields are replaced with the string
"redacted":access_tokenrefresh_tokenid_token