---
title: "Calling a Protected API from an iOS Swift App"
description: "A step-by-step guide to leveraging OAuth 2.0 when accessing protected APIs via an iOS app built with Swift and integrated with Auth0."
authors:
  - name: "Peter Fernandez"
    url: "https://auth0.com/blog/authors/peter-fernandez/"
date: "Jul 26, 2024"
category: "Developers,Tutorial,iOS"
tags: ["swift", "authentication", "mobile", "native"]
url: "https://auth0.com/blog/calling-protected-apis-from-ios-swift/"
---

# Calling a Protected API from an iOS Swift App

As an iOS Swift developer, at some point, you'll likely need to add user authentication - or, as it's more commonly referred to, _login_ and _logout_ - to your app. Hopefully, you'll have integrated this with Auth0. But if not - or if you're still deciding whether user authentication is something you do actually need - I'd highly recommend you start by visiting either [Get Started with iOS Authentication using SwiftUI, Part 1: Login and Logout](https://auth0.com/blog/get-started-ios-authentication-swift-swiftui-part-1-login-logout/) or [Get Started with iOS Authentication using Swift and UIKit](https://auth0.com/blog/get-started-ios-authentication-swift-uikit/) (depending on your preference) before going any further. In this article, I will show you how to configure Auth0 to deliver an [OAuth 2.0](https://auth0.com/intro-to-iam/what-is-oauth-2) **Access Token** that will allow you to safely, securely, and on behalf of a user, call a protected API from within your app. For clarification, this will be some first-party (custom) protected API that you build/own rather than some third-party API provided by Facebook, Google, Microsoft, or the like; that's a topic for another time 😉. 


## What Is an OAuth 2.0 Access Token

OAuth 2.0 allows the generation of an Access Token for use as part of a call to a protected end-point - a.k.a. an API - on behalf of a user and with that user's consent. This is often referred to as _Delegated Authorization_ workflow and typically involves using an _Authorization_ Server_ like Auth0. An Access Token, often referred to as a _Bearer Token_ - and usually supplied as the `Authorization: Bearer` header - acts as the security credential for a REST-based API call, providing a more secure and more auditable mechanism than either _Basic_ Authentication_ or an _API Key_ - particularly for a native app or SPA - Single Page Application - where the threat landscape can be more complex than that for a Regular Web Application. Though they can be similar, e.g., both being in [JWT](https://auth0.com/docs/secure/tokens/json-web-tokens) format in Auth0, an OAuth 2.0 Access Token is different from an OIDC ID Token - which is a token intended for application use and created as part of OpenID Connect workflow; you can read more about this [here](https://auth0.com/blog/id-token-access-token-what-is-the-difference/).      


## Configuring Auth0

In this blog post, I'm going to show you how to leverage Auth0 (acting as an OAuth 2.0 Authorization Server) to generate an Access Token that'll allow your Swift app to call your (custom) API securely. To do this, I'm going to build on the [Get Started with iOS Authentication using SwiftUI, Part 1: Login and Logout](https://auth0.com/blog/get-started-ios-authentication-swift-swiftui-part-1-login-logout/) blog post I mentioned previously; I'll also continue with the convention in that article of using the 🛠 emoji if you’d like to skim through the content while focusing on the build and execution steps. 

Why SwiftUI? Well, we're not too concerned with the UX at this point, so whether you use SwiftUI or Swift with UIKit is something of a moot point. Access Token generation requires Authentication as a pre-requisite, and leveraging the IdP (a.k.a. Identity Provider) capabilities in Auth0 is typically a good way of doing that.

🛠 Let's start by using the [Dashboard](https://auth0.com/docs/get-started/auth0-overview/dashboard) to configure Auth0. I'm going to register a new API by clicking the _Create API_ button near the top right of the page shown below (note: the Auth0 tenant I'm using is a _Production_ class tenant, but yours will probably say _Development_; for the purpose of this article, the tenant classification is irrelevant):

![Registering an API in Auth0](https://images.ctfassets.net/23aumh6u8s0i/7nWWofwe3T91fkeexOTFMk/3f5cdf0072bb8a8d25af483d05909b36/Create_API_Page.png)


This will bring up the following dialog from which I can create my API definition:

![Registering an API in Auth0](https://images.ctfassets.net/23aumh6u8s0i/r7bUD62B5Iege3UtqNeBT/c43e35142b19496988b6e8b9b6fc9da7/Create_API_Dialog.png)

There are a few parts to this dialog, so let's go through them one by one:

* _Name_ is the symbolic name for your API, and you can change it later if you wish.
* _Identifier_ is a value in URI format that **cannot** be changed later. This identifier represents the (custom) `audience` value we'll be using subsequently; being a URI, it has a similar structure to a URL, but instead, it is the symbolic identifier for the API, **not** where the API lives.
* _Signing Algorithm_ indicates the algorithm used to sign the Access Token, and it's almost always preferable to leave this as the default `RS256`. In Auth0, an Access Token is, in a similar fashion to an ID Token, typically in JWT format and likewise has a signature component. While Auth0 supports asymmetric signing (`RS256`) using a public-private key pair and symmetric signing (`HS256`; using a single shared key), the former is almost always recommended over the latter from a security and convenience perspective.    

🛠 I'm not going to go into the details of the API implementation here - I'll leave you, dear reader, to follow up on the [Auth0 Developer Center](https://developer.auth0.com/resources/code-samples) _Backend API_ samples or the like at your leisure. For now, I'm going to go ahead and use some sample values; feel free to populate the following with something similar for your API scenario:

* _Name_: `MyAPI`
* _identifier_: `https://myapi.com`
* _Signing Algorithm_: `RS256` (the default)

 🛠 Click **Create**, and the (custom) API configuration page for the app should eventually appear. The page will typically start at the _Quickstart_ section, which will give you some examples for configuring popular API technology stacks; this one shows a sample configuration for _Node.js_ with _Express_, for example:

![Configuring an API in Auth0](https://images.ctfassets.net/23aumh6u8s0i/6Kv0JbjTHXyLaGh2cUTmgm/d12c8e61b78f381780940c3711495131/Configure_API_Page.png)


### Settings

At this point, I want to focus on two specific aspects of API configuration in Auth0, and we'll start with the details on the _Settings_ tab. Click the _Settings_ tab, and if you scroll down a little, you'll see a page that looks similar to the following; the fields you will have scrolled past to arrive at the display illustrated below will be showing immutable information about the API configuration - such as the internal _Id_ and (custom) `audience` _identifier_ - as well as giving you the option to change the symbolic API _Name_:

![Configuring API Settings in Auth0](https://images.ctfassets.net/23aumh6u8s0i/4qKLkGVfTwenNTdZmskwU8/d15c5b464dd73114d3684a54f2cc158a/Configure_API_Page__Settings_.png)

* _Token Expiration (Seconds)_: we'll leave it set to the default value for now. However, this is a value you'll likely want to revisit at some point, as it controls the expiry of the Access Token issued by Auth0 for the given (custom) `audience` _identifier_. This is important, particularly for security-sensitive operations - such as those involving financial transactions - where you'll likely want to keep this value as low as possible, meaning that an Access Token will only have a lifetime just long enough for the operation in question and so reduce the threat landscape should the token get inadvertently leaked.
* _Allow Skipping User Consent_ will allow an application defined in Auth0 - a.k.a. a first-party application by default; see [here](https://auth0.com/docs/get-started/applications/confidential-and-public-applications/first-party-and-third-party-applications) for more details - to skip interactive user **consent** when an Access Token is requested. A fundamental part of the OAuth 2.0 specification allows a user to explicitly consent to what an application can do on their behalf. I'll talk more about it in the [Permissions](#Permissions) section below. For first-party applications - i.e., an application that you also own and build in addition to the (custom) API - consent is often implied, so with this setting, Auth0 gives you the option to do away with unnecessary user interaction. 

All of the other settings we can leave for now.

### Permissions

The other aspect I want to discuss when it comes to API configuration in Auth0 is _Permissions_ - accessed via the _Permissions_ tab, as shown in the diagram below. The term _Permission_ can be a little confusing as it has more than one meaning in an Auth0 context - particularly when Auth0 [RBAC](https://auth0.com/docs/manage-users/access-control/rbac) (i.e., Role Based Access Control) is enabled against an API. I'm not going into more details here, but suffice it to say that we will define at least one `scope` - the default meaning for _Permission_ in Auth0 when RBAC is **not** enabled against an API. If you want to read more, the Auth0 Blog article [here](https://auth0.com/blog/permissions-privileges-and-scopes/) can provide you with additional details.

![Configuring API Permissions in Auth0](https://images.ctfassets.net/23aumh6u8s0i/14TQLdRPAFO3ucLRjJ6PNG/677bf8fb2e14f7d7c34bd9984c56786b/Configure_API_Page__Permissions_.png)

`scope` is part of OAuth 2.0 _Delegated Authorization_ and defines what an application can do on behalf of a user and with that user's consent. While it's entirely feasible to omit `scope` definitions - the OAuth 2.0 spec does not make them mandatory - doing so can lead to problematic situations, for example:

* Using an unscoped Access Token essentially violates the [Principle of Least Privilege](https://www.okta.com/identity-101/what-is-least-privilege-access/) in that such a token would be valid against any API route.
* There is no mechanism for a user to rescind consent on one or more specific scopes. This can make following the likes of GDPR or other regulatory compliance problematic.
* If an API is opened up to a Third-Party application, it becomes impossible to comply with the OAuth 2.0 spec without going back and refactoring both the API and the (custom) API definition in Auth0.    

🛠 So we're going to define at least one _permission_. In the _Permission_ field, enter something like `read:events`, and in the _Description_ field, enter a suitable description, such as `Read access to defined Events`. Click **+ Add**, and the page should be updated in line with the image below:

![API Permissions added in Auth0](https://images.ctfassets.net/23aumh6u8s0i/5fWXJa7FPndqZWjsOAxyZV/f486c41856c67e869f8f4256d17f4dbf/Configure_API_Page__Permissions_Added_.png)

Ok. That's all we need to do for now in Auth0, so let's look at how you request an Access Token for use when calling your API.

## Requesting an Access Token

In this section, we're going to see how to request an Access Token from Auth0. As previously mentioned, I'm going to build on the [Get Started with iOS Authentication using SwiftUI, Part 1: Login and Logout](https://auth0.com/blog/get-started-ios-authentication-swift-swiftui-part-1-login-logout/) article I mentioned previously, and also continue with the convention(s) that the article uses - like employing the 🛠 emoji for those of you who'd like to skim through the content while focusing on the build and execution steps.

### Updating the Project

🛠 From the completed code as part of [Get Started with iOS Authentication using SwiftUI, Part 1: Login and Logout](https://auth0.com/blog/get-started-ios-authentication-swift-swiftui-part-1-login-logout/) - either the code you completed as part of the walkthrough or found in the `iOS SwiftUI Login (completed)` directory as part of the download - open the project in Xcode (if it isn't already) and update the `login()` function in the manner illustrated below. The rest of the code should remain unchanged. You can also download all the code we're going to be creating from [this GitHub repository](https://github.com/auth0-blog/auth0-swift-protected-api-call) 

```swift
// [ 📄 ContentView.swift ]

  func login() {
    Auth0
      .webAuth()
      .audience("https://myapi.com")  // 1
      .scope("openid profile email read:events")  // 2
      .start { result in
        switch result {
          case .failure(let error):
            print("Failed with: \(error)")

          case .success(let credentials):
            self.isAuthenticated = true
            self.userProfile = Profile.from(credentials.idToken)
            print("Credentials: \(credentials)")
            print("ID token: \(credentials.idToken)")
            print("Access token: \(credentials.accessToken)") // 3
        } 
      }
  }
```

The notes below correspond to the numbered comments above:

1. Add the `audience` parameter specifying the _Identifier_ from the (custom) API you created in the [_Configuring Auth0_](#Configuring-Auth0) section above.
2. Add `scope` to include the `read:events` scope defined in the [_Permissions_](#Permissions) section (above). Because we'll override the default value, we'll also need to explicitly specify the OIDC scopes typically included by default - namely, `openid`, `profile`, and `email`. You can read more about these [here](https://auth0.com/docs/get-started/apis/scopes/openid-connect-scopes).
3. Add the `print` line to display the returned Access Token in the XCode. This will help with debugging - especially from the perspective of decoding the returned Access Token. 

### Running the App

🛠 Now run the app (either in the Simulator that comes with XCode or on a real device) and watch what happens when you press the _Log in_ button. Nothing very different, right?!

Remember that _Allow Skipping User Consent_ option in the [Settings](#Settings) section (discussed above) that's enabled by default? Well, this disables Auth0 from displaying the consent dialog because the definition in Auth0 that's being used is for a first-party application (the default when an _Application_ is defined via the Auth0 Dashboard). If that option had been disabled - or the definition was for a third-party application - then you would have seen a screen similar to that shown below when run for the first time:

![Consent when requesting an Access Token for the first time](https://images.ctfassets.net/23aumh6u8s0i/228seSTve0tQh6gutvhH9r/8caeb5eee94595e05e6d7d373b562272/requesting_an_access_token__consent__720.png)

### Information returned.

Whilst you won't necessarily _see_ anything different occur, there are some changes in the information that will have been returned from Auth0. Firstly, in XCode, you'll see that the _credentials_ `print` statement in the code above shows an `accessToken: "<REDACTED>"` line in the debug console log, an `expiresIn` value and also `scope: Optional("openid profile email read:events")`. We independently print the value of the `accessToken`, so I'll discuss that in just a second; `scope` now echoes the values from the `scope` requested, and the `expiresIn` is now calculated based on the _Token Expiration_ discussed earlier in the [Settings](#Settings) section above.

The `accessToken` that's returned is what we're going to use when calling our API. Ordinarily, an Access Token should be treated as opaque from the perspective of the application. However, because in Auth0, an Access Token is delivered in JWT format - at least when a (custom) API `audience` is specified, the default being JWE format when no specific `audience`` is used - we can take the value and decode it using [jwt.io] (https://jwt.io/). Doing so should yield something similar to the following (portions redacted for security):

![Access Token decode via jwt.io](https://images.ctfassets.net/23aumh6u8s0i/2lVUg854dKQYnw5ResGEC8/028ece91b7ab9ad55e8bc4916025d759/Access_Token_via_JWTio.png)

Of particular note, you'll see the `https://myapi.com` identifier included in the `audience` claim and the scopes we specified included as part of the `scope` claim. You'll also notice the `sub` claim, containing the Auth0 internal identifier for the user on behalf of whom the Access Token has been generated. All of these are standard claims as defined by the OAuth 2.0 specification, and any of the claims displayed would typically be used by the resource server (i.e. the API) to determine the validity of a request. See [here](https://auth0.com/docs/secure/tokens/access-tokens/validate-access-tokens) in the Auth0 Docs for further information.  

## Using an Access Token

Now, let's put the Access Token to use. 

🛠 Returning to the XCode project, update the code as shown in the illustration below to save the credentials returned from the Auth0 `webAuth()` request. We'll likely want to use said credentials in a number of places within the app, and we can use the Auth0-provided `CredentialsManager` to safely and securely store these. I'm not going to go into the process in too much detail here, but you can read more about it by following the link to the Auth0 SDK documentation. Or, alternatively, follow [this](https://github.com/auth0/Auth0.swift/blob/master/EXAMPLES.md#credentials-manager-ios--macos--tvos--watchos) link to the _Examples_ section in the SDK GitHub repo.    

```swift
// [ 📄 ContentView.swift ]

  func login() {
    let credentialsManager = CredentialsManager(authentication: Auth0.authentication()) // 1 

    Auth0
      .webAuth()
      .audience("https://myapi.com")
      .scope("openid profile email read:events")
      .start { result in
        switch result {
          case .failure(let error):
            print("Failed with: \(error)")

          case .success(let credentials):
            self.isAuthenticated = true
            self.userProfile = Profile.from(credentials.idToken)
            // Pass the credentials over to the Credentials Manager
            let didStore = credentialsManager.store(credentials: credentials) // 2
            print("Credentials: \(credentials)")
            print("ID token: \(credentials.idToken)")
            print("Access token: \(credentials.accessToken)")
        } 
      }
  }  
```

 Some notes that correspond to the numbered comments above:
 
 1. Create a reference to the Auth0 `CredentialsManager`.
 2. Store the returned credentials for later use.

!🛠 Now we need to make a call to the actual API implementation, passing the Access Token as an `Authorization: Bearer` within the HTTP request header. I've created a separate module to isolate this functionality and, in doing so, will (hopefully) make the process easier to follow; I've added some notes below, too, for things that I feel are relevant:

```swift
// [ 📄 APICallView.swift ]

import SwiftUI
import Auth0

struct Event: Identifiable, Codable {  // 1
    let id: Int
    let title: String
    let body: String
}

enum NetworkError: Error {  // 2
    case badUrl
    case invalidRequest
    case badResponse
    case badStatus
    case failedToDecodeResponse
}

class WebService: Codable {
    func credentials() async throws -> Credentials {  // 3
        let credentialsManager = CredentialsManager(authentication: Auth0.authentication())
        
        return try await withCheckedThrowingContinuation { continuation in
            credentialsManager.credentials { result in
                switch result {
                case .success(let credentials):
                    continuation.resume(returning: credentials)
                    break

                case .failure(let reason):
                    continuation.resume(throwing: reason)
                    break
                }
            }
        }
    }
    
    func downloadData<T: Codable>(fromURL: String) async -> T? {
        do {
            guard let url = URL(string: fromURL) else { throw NetworkError.badUrl }
            var request = URLRequest(url: url)
            let credentials = try await credentials();
            
            /* Convention is for an Access Token to be supplied as Authorization Bearer in the header of an HTTP request. Apple's documentation is somewhat ambiguous when it comes to how to do this, so for the purpose of this example I'll follow the advice suggested at https://ampersandsoftworks.com/posts/bearer-authentication-nsurlsession/
             */
            request.setValue("Bearer \(credentials.accessToken)", forHTTPHeaderField: "Authorization") // 4
            
            let (data, result) = try await URLSession.shared.data(for: request)
            guard let response = result as? HTTPURLResponse else { throw NetworkError.badResponse }
            guard response.statusCode >= 200 && response.statusCode < 300 else { throw NetworkError.badStatus }
            guard let decodedResponse = try? JSONDecoder().decode(T.self, from: data) else { throw NetworkError.failedToDecodeResponse }
            return decodedResponse
        } catch NetworkError.badUrl {
            print("There was an error creating the URL")
        } catch NetworkError.badResponse {
            print("Did not get a valid response")
        } catch NetworkError.badStatus {
            print("Did not get a 2xx status code from the response")
        } catch NetworkError.failedToDecodeResponse {
            print("Failed to decode response into the given type")
        } catch {
            print("An error occurred downloading the data")
        }
        
        return nil
    }
}

class EventViewModel: ObservableObject {
    @Published var eventData = [Event]()
    
    func fetchData() async {
        guard let downloadedEvents: [Event] = await WebService().downloadData(fromURL: "<API URL goes here>") else {return} // 5
        DispatchQueue.main.async {
            self.eventData = downloadedEvents
        }
    }
}

struct APICallView: View {
    @StateObject var vm = EventViewModel()
    
    var body: some View { // 6
        List(vm.eventData) { event in
            HStack {
                Text("\(event.id)")
                    .padding()
                    .overlay(Circle().stroke(.blue))
                
                VStack(alignment: .leading) {
                    Text(event.title)
                        .bold()
                        .lineLimit(1)
                    
                    Text(event.body)
                        .font(.caption)
                        .foregroundColor(.secondary)
                        .lineLimit(2)
                }
            }
        }
        .onAppear {
            if vm.eventData.isEmpty {
                Task {
                    await vm.fetchData()
                }
            }
        }
    }
}
```

The following notes correspond to the numbered comments above:

1. Sample `Event` object structure for the data delivered from the API
2. A sample enumeration for potential errors generated as a result of calling the API
3. Wrapping the Auth0 `CredentialsManager` for _Async/Await_ operation
4. Adding the Access Token as the `Authorization: Bearer` header
5. Prefer to get the API URL from some _.plist_ file entry
6. Displaying the events returned from the API

### API call UX

To make it easy to access the API, I've updated the existing function to add a convenient button that will trigger the API call; the code below shows the changes made to the `struct ContentView` declaration, with the customary notes added for good measure.   

```swift
// [ 📄 ContentView.swift ]

  @State private var isAuthenticated = false
  @State private var isAPICall = false // 1
  @State var userProfile = Profile.empty
  
  var body: some View {
      
    if isAuthenticated {
        if isAPICall {
            
            APICallView() // 2
            
        } else {
            // “Logged in” screen
            // ------------------
            // When the user is logged in, they should see:
            //
            // - The title text “You’re logged in!”
            // - Their photo
            // - Their name
            // - Their email address
            // - The "Log out” button
            
            VStack {
                
                Text("You’re logged in!")
                    .modifier(TitleStyle())
                
                UserImage(urlString: userProfile.picture)
                
                VStack {
                    Text("Name: \(userProfile.name)")
                    Text("Email: \(userProfile.email)")
                }
                .padding()
                
                HStack {
                    
                    Button("Log out") {
                        logout()
                    }
                    .buttonStyle(MyButtonStyle())
                    
                    Button("Call API") {  // 3
                        isAPICall = true;
                    }
                    .buttonStyle(MyButtonStyle())
                    
                } // HStack
                
            } // VStack
        }
    
    } else {
      
      // “Logged out” screen
      // ------------------
      // When the user is logged out, they should see:
      //
      // - The title text “SwiftUI Login Demo”
      // - The ”Log in” button
      
      VStack {
        
        Text("SwiftUI Login demo")
          .modifier(TitleStyle())
        
        Button("Log in") {
          login()
        }
        .buttonStyle(MyButtonStyle())
        
      } // VStack
      
    } // if isAuthenticated
    
  } // body

```
 
 1. Added a new state flag
 2. Trigger the rendering API call results 
 3. Button to update the added state flag trigger 


#### Building a sample API

As mentioned, I won't be going into the specifics of the API implementation here. However, for a personal SaaS project I'm working on, I've been experimenting using the _Amazon API Gateway_ and have been following [this](https://aws.amazon.com/blogs/apn/building-a-secure-saas-application-with-amazon-api-gateway-and-auth0/) Amazon Blog article; you probably won't need to leverage any of the SaaS aspects - like the [Auth0 Organizations](https://auth0.com/docs/manage-users/organizations) feature - however, that article does a pretty good job of describing the (Access) Token validation process...at least in an AWS context. Below are some screenshots of my implementation - a simple API that returns a list of events - which might help you if you decide to go a similar route 😎

![AWS API Gateway Authorizer](https://images.ctfassets.net/23aumh6u8s0i/7zkRyhUXnjRQz7mQCGUFTS/a8c499f5117bcb114bf5b48b9526ef84/AWS_API_Gateway_Authorization.png)

![AWS API Gateway Lambda Function](https://images.ctfassets.net/23aumh6u8s0i/4xPKJEO8krtLc12axd83kj/48c16c80ea8a9fccd6cbead4cedd5a6b/AWS_API_Lambda_Function.png)

My simple API function is implemented in Node.js, but you can implement an API using any backend language (e.g. Python, PHP, Ruby, etc.) together with any server-side - or server-less - platform. Sticking with an Apple theme and also staying with AWS, here's a great example of how you can leverage server-side Swift (in a serverless environment) to build an API: 

<include 
    src="LinkCard" 
    title="Create an API in Swift and Deploy It to AWS Lambda" 
    link="https://auth0.com/blog/create-an-api-in-swift-and-deploy-it-to-aws-lambda/" 
    description="Learn how to create and deploy a serverless HTTP API using Swift and AWS Lambda." 
    img="https://images.ctfassets.net/23aumh6u8s0i/1z9What44b3C5uk7xZJ4vC/a3748cb5c692b7aecf895e4b5d577c71/swift-hero.jpg"
/>

## Refreshing an Access Token

Using a Refresh Token is typically the recommended approach in a mobile app environment, so, as a follow-up, you'll definitely want to check out my follow-on article on the subject when you get the chance:

<include 
    src="LinkCard" 
    title="Using a Refresh Token in an iOS Swift App" 
    link="https://auth0.com/blog/using-a-refresh-token-in-an-ios-swift-app/" 
    description="A step-by-step guide to leveraging OAuth 2.0 Refresh Tokens in an iOS app built with Swift and integrated with Auth0." 
    img="https://images.ctfassets.net/23aumh6u8s0i/76Y6z74r3hodOC5gvx4Zmk/497c749edab8f7a9651fea3193a27e19/ios_hero_2021_2.jpg"
/>

## Where to Go Next

Don't forget to check out all the code we created by visiting [this GitHub repository](https://github.com/auth0-blog/auth0-swift-protected-api-call). And, of course, feel free to comment below and tell us what you think - we always love to hear feedback, positive or otherwise, as it helps us to improve our content! Thank you. Aside from that, here are some additional resources you might like to follow up on that can help you on your journey. Well, that's all I have for now. Have fun, and I'll catch up with you next time! 😁

* [_Auth0 iOS/macOS Quickstart_](https://auth0.com/docs/quickstart/native/ios-swift/01-login)
* [_iOS SwiftUI Developer Guides_](https://developer.auth0.com/resources/guides?language=swift)
* [_Auth0 Zero Index Newsletter_](https://developer.auth0.com/newsletter)