Auth0.swift SDK

repository·master·Indexed 19 days ago

https://github.com/auth0/auth0.swift

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 secure token storage in the Keychain, and direct API clients for Authentication and Multi-Factor Authentication (MFA).

Tokens
52.2K
Snippets
142
Records
184
Agent score
64%

What's inside Auth0.swift

  1. Overview of Auth0.swift

    master
    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).
  2. Overview of the Auth0 Swift SDK components

    master

    The 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.
  3. What is DocsVersions and how does it work?

    master

    DocsVersions 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 shared versions.json file.

    Key features include:

    • Automatic Versioning: Reads versions from Auth0/Version.swift or 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.
  4. Identify MFA requirements in Authentication flows

    master

    When handling errors from the Auth0.authentication() flow (rather than the MFA client), use the following properties on AuthenticationError to 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 code property 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)")
            }
        }
  5. Use the My Account API to manage user accounts

    master

    The 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.
  6. Understand the architectural patterns in Auth0.swift

    master

    The 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 WebAuth API uses a fluent builder pattern for configuration, such as webAuth.scope("openid").connection("google-oauth2").start().
    • Typed Result Aliases: Each subsystem uses specific typed result aliases, such as AuthenticationResult<T>, WebAuthResult<T>, CredentialsManagerResult<T>, and MyAccountResult<T>.
    • Thread Safety: Components like CredentialsManager are Sendable and use NSLock internally to ensure thread safety during concurrent operations.
  7. Swift 6 Concurrency changes in v3

    master

    To support Swift 6, Auth0.swift v3 has introduced several concurrency-related changes:

    • WebAuth Sendability: WebAuth and its associated typealiases now conform to Sendable.
    • 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 in DispatchQueue.main.async.
    • JWTDecode Upgrade: The underlying JWTDecode.swift dependency has been upgraded to v4.0.0.
  8. Read the `act` claim from the ID token

    master

    When 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. The act claim is exposed via the UserInfo type through the ActClaim class.

    To read it, you may need to decode the ID token (e.g., using JWTDecode.swift) and map it to UserInfo:

    • sub: The subject identifier of the acting party.
    • act: A nested ActClaim for delegation chains.
    • additionalClaims: Extra claims (e.g., org, role).

    You can also access it directly from the CredentialsManager via credentialsManager.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)")
        }
    }
  9. Handle main thread result delivery in v3

    master

    In 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.async or .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)
            }
        }
    }
  10. Handle IPSIE session expiry [Early Access]

    master

    When using enterprise connections (OIDC/Okta) with session-expiry enforcement enabled, Auth0 emits a session_expiry claim. CredentialsManager automatically enforces this ceiling. If the ceiling is reached, methods like credentials(), ssoCredentials(), and apiCredentials() will clear the stored credentials and return CredentialsManagerError.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)")
        }
    }
  11. How to test Combine publishers and async code

    master

    When 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 await keyword:

    await expect(value).to(...)

    // Correct way to test async values
    await expect(value).to(equal(expectedValue))
  12. Automatic token redaction in logs

    master

    To 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_token
    • refresh_token
    • id_token