DevDay 2022: Keynotes, workshops, and more. Join us in Sydney, London & Berlin.Register for Free
iOS

Get Started with iOS Authentication using SwiftUI, Part 1: Login and Logout

Learn how to use Auth0 to implement basic login and logout in iOS apps built with SwiftUI.

Last Updated On: March 31, 2022

iOS

Get Started with iOS Authentication using SwiftUI, Part 1: Login and Logout

Learn how to use Auth0 to implement basic login and logout in iOS apps built with SwiftUI.

Last Updated On: March 31, 2022

If you’re an iOS developer who’s new to SwiftUI and authentication with Auth0, you’re in for a treat. In this tutorial, you’ll build an app in SwiftUI that implements basic login and logout using Auth0!

This tutorial covers using version 2.0.0 of the Auth0.swift SDK to implement login/logout in an iOS app written using the Swift programming language and the SwiftUI framework. In the process, you’ll get a quick introduction to the basics of our newly revised Swift SDK and how to use it with Apple’s SwiftUI framework. You’ll also become familiar with the Auth0 dashboard and learn how to use it to register applications and manage users.

Look for the 🛠 emoji if you’d like to skim through the content while focusing on the build and execution steps.

Apple’s SwiftUI Framework

SwiftUI logo

SwiftUI is a user interface toolkit and “the new way” for building apps that Apple introduced in 2019. With SwiftUI, you build user interfaces using Swift code with a declarative approach, which means that you specify how the UI should look and behave under different states. You don’t have to specify how the UI moves between those states — it takes care of that for you. If you know React programming, you’ll find SwiftUI familiar.

The SwiftUI approach is quite different from the one used by UIKit, iOS’ original UI toolkit, which dates back to 2007. With UIKit, you build user interfaces using Interface Builder, a drag-and-drop layout tool to build the app’s views graphically. You connect UI elements to variables and methods in the app’s view controllers using outlets and actions. UIKit uses an imperative approach, which means that you define how the program moves between states and how the UI should look and behave in those states.

Auth0 and the Auth0.swift SDK

Auth0 logo

Adding login and logout to an app may seem like a simple task — until you try it. You have to handle the many ways to log in, confirm email addresses and passwords, manage users, and handle security and scalability. Each of these issues has dozens of considerations, risks, issues, and edge cases.

Auth0 solves this problem. With Auth0 and a few lines of code, your app can have a full-featured system that supports logging in with a username/password combination, single sign-on and social accounts, passwordless login, biometrics, and more. You won’t have to handle the “behind the scenes” issues, either! Instead, you can focus on your app’s main functionality.

Auth0.swift is the Auth0 SDK for all Apple platforms: not just iOS, but macOS, iPadOS, watchOS, and tvOS. It’s our third most-used SDK, accounting for 11% of all API requests made to our systems. If you’re building an Apple device application that needs to authenticate or authorize its users, you need this SDK!

The newest version of Auth0.swift, version 2.0.0, incorporates what we’ve learned from securing applications on Apple devices over the past five years. If you’ve used earlier versions, you’ll appreciate its updated error handling, support for async/await and Combine, improved default configuration, new documentation, and that we removed deprecated methods and legacy features. If you’re new to Auth0, you’ll be pleasantly surprised at how little code you’ll need to write to add authentication to your apps.

What You’ll Build

In this tutorial, you’ll build a simple, single-screen iOS app that will allow the user to log in and log out using Auth0. While logged in, the screen will have a different appearance and show the user their name, email address, and photo from their profile.

Instead of building the app from a starter project, you’ll build it “from scratch,” starting with selecting FileNewProject… from Xcode’s menu bar.

A quick tour of the app

When you launch the completed app, you’ll see an logo icon, some status text, the app’s title, and a Log In button:

The app’s “Logged out” screen, featuring the app’s title, “SwiftUI Login Demo” and a “Log in” button.

The Log in button takes the user to the Auth0 Universal Login screen, which appears in a custom browser window:

The Auth0 Universal Login web page, with Auth0 logo and “email address” and “password” fields.

When you use Auth0 to add login/logout capability to your apps, you delegate authentication to Auth0’s Universal Login, a cross-platform webview-based page that supports logging in, signing up for an account, and other authentication flows. In this exercise, you’ll use the default “look and feel” for the login page, but you can customize it to match your app or organization’s branding.

If the user logs in successfully, the Universal Login screen and its browser window disappear, and the user returns to the app, which now displays selected information from the user’s profile, namely their profile photo, name, and email address, as well as a Log out button:

The app’s “logged in” screen, featuring the text “Logged in” and displaying the user’s picture, name, and email address.

The Log out button logs the user out and returns them to the initial screen.

Prerequisites

Here’s a list of the software, hardware, and knowledge you’ll need for this exercise.

An Auth0 account

The app you will write for this article’s exercise uses Auth0 to provide login and logout functionality. As its developer, you’ll need an Auth0 account. You can sign up for a free account, which lets you add authentication for up to 10 applications and 7000 users. This should be enough for evaluating the platform, as well as for prototyping, development, and testing.

An iOS development setup

To develop applications for any Apple hardware, you need a Mac computer running Xcode, Apple’s integrated development environment:

  • Most Macs from mid-2013 or later with at least 8 GB RAM (16 GB preferred).
  • One of the more recent releases of macOS, preferably Big Sur or Monterey.
  • Xcode version 11.0 (September 2019) or later. When writing this article, I used the current version: version 13.2.1 (13C100), released on December 17, 2021.

An iOS device, virtual or real

Xcode comes with the Simulator, an application that creates virtual devices that simulate recent models of the iPhone, iPad, and iPod Touch models, all of which run iOS 15.

To install earlier versions of iOS for the Simulator, select Preferences… from the Xcode menu, followed by the Components tab. You’ll see a list of older versions of not just iOS, but watchOS and tvOS as well.

One of the benefits of using the Simulator is that you don’t need an Apple Developer account — free or paid — to use it.

While the Simulator is convenient, there’s no substitute for an actual physical device. It provides a more realistic testing experience, since you can’t do certain things on the Simulator, such as motion/tilt sensing and augmented reality.

To deploy an app directly to a device for testing, you need a free Apple Developer account, which in turn requires an Apple ID. If you don’t have an Apple ID, sign up for one here. Once you have an Apple ID, go to developer.apple.com, click the Account at the top of the page, and sign in.

You need to register the device in your developer account to deploy apps to it; you do so on this page in the Apple Developer site. You can register up to 100 devices per membership year. You’ll need to provide the device’s UDID (Unique Device IDentifier), and you may find this site helpful. Once you’ve registered a device, you can deploy apps directly to it; see Distributing Your App to Registered Devices for more information.

To deploy apps to the App Store, you’ll need a paid account. For more details, see the Apple Developer enrollment page.

To find out more about running apps on virtual and real iOS devices, start with Apple’s article, Running Your App in the Simulator or on a Device.

Some knowledge of Swift and structs

While not completely necessary, it would help if you were familiar with the Swift programming language and iOS development. If these are new to you, the Swift programming language, or the UIKit framework, try this Apple tutorial: Getting Started with Today,.

SwiftUI relies heavily on structs, so you may find it helpful to review their basics. You may find Hacking with Swift’s article, How to create your own structs, helpful.

Make a New SwiftUI App

Let’s start by building a new SwiftUI app. Once we have a basic app working and you’ve learned about a few SwiftUI interface elements, we’ll incorporate Auth0 authentication and then finish the exercise by adding some user experience flair.

Start from scratch

🛠 Launch Xcode and create a new project by opening the File menu and selecting NewProject....

Xcode will present this dialog box, where you’ll choose a project template for the app you’ll create. Each template generates the necessary files for different applications, including general-purpose apps, videogames, augmented reality apps, and add-ons that add custom features to iMessage and Safari.

Xcode’s “Choose a template for your new project” dialog, with “iOS” and “App” selected.

🛠 For this exercise, we want to create a general-purpose app for iOS, so select the iOS tab, then select App project template, which will be at the upper left corner of the collection. Click the Next button to confirm the selection.

Xcode will display the next dialog box, where you’ll give the project its human- and computer-friendly names and specify which programming language and framework you’ll use:

Xcode’s “Choose options for your new project” dialog, with the  “Product Name” field filled with “SwiftUI Login Demo”.

🛠 In this dialog box, do the following:

  • Enter a name for the project into the Product Name field. For this exercise, I used the name SwiftUI Login Demo.
  • Select a team from the Team menu. If you haven’t created a development team yet and want to continue with this exercise without going through the process of signing up for an Apple developer account and creating a team, select None. This will let you deploy the app to the Simulator but not to a device.
  • Enter com.example into the Organization Identifier field.
  • Select SwiftUI from the Interface menu.
  • Select Swift from the Language menu.
  • Click the Next button.

🛠 Xcode will show one more dialog box — this one lets you specify where your project and its files will be stored. Select a location.

Once you’ve completed the steps above, Xcode will generate the files for your project and display the main window:

The Xcode window displaying the newly created project, with an empty Preview pane.

Whenever you create a new SwiftUI project using the App template, Xcode generates a single view named ContentView, whose contents are the first thing you see once it creates the project.

This is ContentView’s initial code, annotated with numbered comments:

import SwiftUI  // 1

// 2
struct ContentView: View {
  
  // 3
  var body: some View {
    
    // 4
    Text("Hello, world!")
      .padding()
  }
}

// 5
struct ContentView_Previews: PreviewProvider {
  static var previews: some View {
    ContentView()
  }
}

Here’s what’s happening in the code marked by the numbered comments above:

  1. Any SwiftUI project file that defines a UI element, whether a whole screen or a single control, must import the SwiftUI library.
  2. In SwiftUI, every UI element is a view — a struct that adopts the View protocol, which defines the functionality that a SwiftUI onscreen element should provide. This particular view, ContentView, defines the app’s single screen.
  3. The View protocol has a single requirement: any type that adopts it must have a body property, which defines the UI element’s appearance and behavior. The body property’s type is some View, which is Swift’s way of saying “some type that adopts the View protocol.” Note that body’s value is determined by a closure, which is a block of code that you can pass to a function.
  4. You’ve probably figured out that Text is a view for displaying text onscreen. Views can be followed by modifiers — methods that change their appearance or behavior. In this case, we’re adding space between the Text view’s contents and edges with the padding() modifier.
  5. When Xcode creates a new file for a view, it generates two structs: one for the view that appears in the app, and one for a preview that appears in the Xcode editor. This struct, ContentView_Previews, generates a preview of ContentView that allows you to see what it will look like without requiring you to compile and run the app.

When editing view files, Xcode divides the editing area in the center of its screen into two areas: a code editor and a preview viewer.

🛠 To see what the app’s user interface will look like, make a selection from the simulator device menu, then click the Resume button in the preview viewer:

The Xcode window, with instructions to select a simulator device and click the “Resume” button.

You should see something like this:

The Xcode window, with the Preview pane displaying a preview of the app.

🛠 You can also choose to see the app in action by running it. Select a Simulator device or connect a real device to your computer and click the Run button:

The Xcode window, with instructions to make sure you’ve selected a simulator device and click the “Run” button.

The Simulator will launch, and you’ll shortly see this:

The Xcode simulator simulating an iPhone 13. Its screen is blank, except for the sentence “Hello, World!” in the center.

Add state and interactivity to the app

It’s time for the app to do more than just display “Hello, World!” Let’s create the app’s two states — logged out and logged in — and provide a way for the user to navigate between them.

When launched, the app will feature title text and a Log in button:

The app’s “Logged out” screen, featuring the app’s title, “SwiftUI Login Demo” and a “Log in” button.

Tapping the Log in button takes you to this screen, which has the text “Logged in” and a Log out button:

The app’s “Logged in” screen, featuring the text “Logged in” and a “Log out” button.

🛠 In Xcode, open the ContentView file and replace the ContentView struct with the following:

struct ContentView: View {
  
  // 1
  @State private var isAuthenticated = false


  var body: some View {

    // 2
    if isAuthenticated {
      
      // 3
      VStack {
        
        Text("Logged in")
          .padding()
        
        // 4
        Button("Log out") {
          isAuthenticated = false
        }
        .padding()
        
      }
      
    } else {
    
      // 5
      VStack {
        
        Text("SwiftUI Login Demo")
          .padding()
        
        // 6
        Button("Log in") {
          isAuthenticated = true
        }
        .padding()
        
      }
      
    } // if isAuthenticated
    
  }
  
}

I’ve marked the code with numbered comments, which are explained below:

  1. This line declares a new private instance variable, isAuthenticated. It starts with @State, which tells SwiftUI a couple of things about it:
    • @State informs SwiftUI that this variable is part of the view’s state, which is the set of variables that affect its appearance and behavior. When the value of any state variable in a view is changed, SwiftUI redraws the view to reflect that change. The value of isAuthenticated will be set to true if the user is logged in and false if the user is logged out. Since this value will affect the app’s appearance, I’ve made it a state variable.
    • @State also allows the struct’s methods to change its value. By default, a struct’s methods can’t change the values of its variables.
  2. The app should display a different screen depending on the value of isAuthenticated. This if statement determines the value that will be assigned to body, which determines the onscreen user interface.
  3. This is the branch of the if statement that executes if the user is logged in. The result of this branch must be a single view, which is a problem: we want to display two views: some text and the Log out button. To work around this limitation, we’ll use a view that acts as a container for other views: VStack, whose name is short for “vertical stack.” It can take up to 10 views, which it displays in a vertical column, with the first view appearing at the top and subsequent views appearing below the topmost view.
  4. The Button view takes two arguments:
    • A string value for the button’s label: “Logged in”.
    • A closure that defines what should happen when the user presses the button: it changes the value of isAuthenticated to false. Since isAuthenticated is a state variable, changing its value causes SwiftUI to redraw ContentView. When that happens, the app will execute the other branch of the if statement.
  5. This is the branch of the if statement that executes if the user is not logged in. The result of this branch is another VStack — this one contains the app’s title and the Log in button.
  6. This Button view is similar to the one for the Log in button, except that it says Log out and sets isAuthenticated to true when pressed.

🛠 If the Resume button is visible in the Preview pane, click it. It will update to display the new user interface.

🛠 Run the app to see it in action. Click the Log in and Log out buttons to go from screen to screen.

Refactor the buttons’ code

As SwiftUI views become more complex, their code often becomes increasingly hard to read. One way to keep them readable is to put code in closures into their own methods.

🛠 Add this extension to ContentView, between ContentView and ContentView_Previews:

extension ContentView {
  
  func login() {
    isAuthenticated = true
  }
  
  func logout() {
    isAuthenticated = false
  }
  
}

🛠 Update the code for the Log out button in ContentView to the following:

        Button("Log out") {
          logout()
        }
        .padding()

🛠 Update the code for the Log in button in ContentView to the following:

        Button("Log in") {
          login()
        }
        .padding()

🛠 Run the app. It will still work the same way, but by extracting the buttons’ closures into their own methods and putting those methods into their own extension, the code will be easier to read and change.

Set Up the App to Integrate with Auth0

Now that you’ve been introduced to a few SwiftUI views and have seen how SwiftUI uses state to configure the user interface, it’s time to change the app to one that uses Auth0 for user authentication.

Install the Auth0.swift package

Let’s take on the first part of this task: setting up the app to integrate with Auth0. We’ll do this by adding the Auth0.swift package to the project.

Auth0.swift is a collection of libraries that allow applications written in Swift to make use of Auth0’s authorization and authentication functionality. It contains these Swift libraries:

There are three ways to install Auth0.swift:

  1. Swift Package Manager, Apple’s dependency manager
  2. Cocoapods, a long-standing third-party package manager first released in 2011 and used in many projects
  3. Carthage, another third-party package manager

I chose to use Swift Package Manager for this tutorial because it’s built into Xcode and doesn’t require additional software. If you’d rather use Cocoapods or Carthage to install Auth0.swift, see these instructions.

🛠 To start the process of installing the Auth0.swift package, open the File menu and select Add Packages.... This window will appear:

The “Add Packages” window.

🛠 Enter the URL for the Auth0.swift package repository into the window’s search field:

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

Xcode will search online and display any packages it finds at the URL. The search should produce a single result: Auth0.swift.

🛠 Select the Auth0.swift package when it appears in the list. In the Dependency Rule menu, select Up to Next Major Version and make sure that the version number in the text field to its right os 2.0.0, then click Add Package:

The “Add Packages” window, with instructions for adding the “Auth0.swift” package.

🛠 You’ll be asked to confirm that you want to add the Auth0.swift package. Click Add Package to reassure Xcode that yes, you want Auth0.swift:

The “Add Packages” window, with a modal window asking the user to select the packages to add.

When Auth0.swift finishes installing, its package will appear in the list under the Package Dependencies tab of the project screen. You’ll see Auth0.swift’s libraries listed in the Project Explorer pane:

Xcode’s “Package Dependencies” tab.

At this point, the functionality contained within Auth0.swift is now available to your app. You’ll start using it once you’ve done all the necessary Auth0 setup.

Add a property list to store Auth0 credentials

In order to use Auth0 to authenticate users, your app needs to:

  • communicate with the appropriate Auth0 tenant, and
  • identify itself to that server.

You do this by providing the app with that tenant’s identifier, a value known as the domain, and the app’s identifier, the client ID. Auth0.swift expects to find these values in a property list (a .plist file), so let’s create one.

🛠 Create a new property list file by right-clicking (or control-clicking) the SwiftUI Login Demo folder in Project Explorer and selecting New File…:

Xcode screenshot, showing the user selecting “File -> New File...”

🛠 In the window that appears, make sure that the iOS tab is selected. Scroll down the list of icons until you see the Property List icon. Select it, then click Next:

Xcode screenshot, showing the selection of the “Property List” file template.

🛠 Name the file Auth0.plist and click Create to create the file:

Xcode screenshot, showing the “Save” dialog box for the property list.

Xcode will display the new Auth0.plist file in a table format. Let’s add two rows to the table, which will hold the domain and client ID values.

🛠 Move the cursor over the Root row to reveal the + button. Click on the + button twice to add two rows:

Xcode screenshot, showing the creation of two new rows in the property list.

🛠 Enter the following values into the two rows:

  • Row 1:
    • Key: Domain
    • Type: String
    • Value: Leave this blank for the time being. You’ll get this value from the Auth0 dashboard.
  • Row 2:
    • Key: ClientId
    • Type: String
    • Value: Leave this blank for the time being. You’ll get this value from the Auth0 dashboard.

Your Auth0 plist file should look like this:

Xcode screenshot, showing the completed property list.

Set Up Auth0 to Integrate with Your App

Now that you’ve set up the app to work with Auth0, it’s time to set up your Auth0 tenant to work with the app. To accomplish this, you’ll do the following:

  1. Add the app to your Auth0 dashboard’s list of registered applications
  2. Gather two pieces of information that the app will need to delegate login/logout to Auth0:
    • Your tenant’s domain
    • The client ID that Auth0 will assign to the app
  3. Provide Auth0 with the necessary callback URLs to contact the app: one to call at the end of the login process and the other to call at the end of the logout process

You’ll need an Auth0 account for this step. Once again, you can sign up for an Auth0 account for free! We’ve taken great care to make the process as painless as possible.

Add the app to the Applications list

🛠 Log into the Auth0 dashboard and select ApplicationsApplications from the menu on the left side of the page.

You will now be on the Applications page, which lists all the applications that you have registered with Auth0. Let’s add your app to the list.

🛠 Start the process of registering a new app by clicking the Create application button near the top right of the page:

The “Applications” page. The reader is directed to click the “Create Application” button.

You’ll see this dialog appear:

The “Create application” dialog. The application’s name is set to “iOS Auth”, and the selected application type is “Native”.

🛠 You’ll need to provide two pieces of information to continue:

  • Enter a name for the app in the name field. It might be simplest to use the same name as your Xcode project (if you’ve been following my example, use the name SwiftUI Login Demo).
  • Specify the application type, which in this case is Native.

🛠 Click Create. The Quick Start page for the app will appear:

The “Quick Start” page. It contains several icons, each one representing an operating system or platform.

This page provides you with ready-made projects for several different platforms that you can use as the basis for an application that delegates authentication to Auth0. You won’t be using any of them in this exercise; instead, you’ll make use of a couple of Auth0 libraries and write the code yourself. It’s more educational — and more importantly, fun — that way.

🛠 Click the Settings tab, which will take you to this page:

The “Application” page’s “Settings” tab.

You’re going to do two critical things on this page:

  1. Get information that the app needs to know about Auth0, and
  2. Provide information that Auth0 needs to know about the app.

Let’s take care of the first one: Getting the information that the app needs, namely the domain and client ID, which you’ll enter into the property list file you created earlier.

🛠 Copy the contents of the Domain field, then switch to Xcode, open the Auth0 property list, and paste the domain value you copied into the Domain row’s Value field.

🛠 Next, go back to the Auth0 dashboard and copy the contents of the Client ID field, then switch to Xcode, and paste the domain value you copied into the ClientId row’s Value field in the property list.

The Auth0 property list in Xcode, with instructions to copy and paste the “Domain” and “Client ID” values into it.

🛠 Return to the Auth0 dashboard and scroll down to the Applications URIs section:

The “Application URIs” section of the “Application” page’s “Settings” tab.

This is where you provide Auth0 with two pieces of information that it needs to know about your app:

  1. The callback URL: the URL that Auth0 will redirect to after the user successfully logs in. There can be more than one of these.
  2. The logout URL: the URL that Auth0 will redirect to after the user logs out. There can be more than one of these.

At this point, you’re probably thinking: “Wait a minute — I’m writing a iOS app using SwiftUI. It doesn’t have web pages that you navigate to using URLs, but Views!”

You’re absolutely right. For native applications, the callback and logout URLs are the same string, and Auth0 sends that string to the app to inform it that a user has logged in or logged out.

The string that native iOS apps use for both the callback URL and the logout URL follow this format:

{BUNDLE_IDENTIFIER}://{YOUR_DOMAIN}/ios/{BUNDLE_IDENTIFIER}/callback

To construct this string, you’ll need your app’s bundle identifier.

🛠 In Xcode, click on the project in the Project navigator, click on the project in the Targets menu, and select the General tab. Copy the bundle identifier value, which you’ll find in the Bundle Identifier field in the Identity section near the top of the center pane:

Getting the bundle identifier from Xcode.

🛠 Copy the URL format string above and make the following changes to create a new URL:

  • Replace {BUNDLE_IDENTIFIER} with the bundle identifier you copied. Note that {BUNDLE_IDENTIFIER} appears twice in the URL — replace it both times.
  • Replace {YOUR_DOMAIN} with your tenant’s domain.

🛠 Enter the URL you just constructed into both the Allowed Callback URLs and Allowed Login URLs fields. Remember, the same URL goes into both fields.

The “Application URIs” section of the page. The reader is directed to enter the callback URL into “Allowed Callback URLs” and “Allowed Logout URLs”.

🛠 You’ve done everything you need to do on this page. Scroll down to the bottom of the page and click the Save Changes button:

The bottom of the page, which features the “Save Changes” button. An arrow directs the reader to click the button.

Create a user if your tenant doesn’t have any

If you just created an Auth0 account, your tenant won’t have any user accounts. You’ll need at least one user account to be able to log into the app. Follow these steps to create a user.

🛠 In the menu on the left side of the Auth0 dashboard, select User ManagementUsers:

The bottom of the page now featuring an expanded “User Management” menu. An arrow directs the reader to expand the “Users” menu item.

The Users page will appear. It lists all the users registered to your tenant. If there are no users, you’ll see the “You don’t have any users yet” message.

The “Users” page. The page says, “You don’t have any users yet”. An arrow directs the reader to click the “Create User” button.

🛠 Click the Create User button to create a new user, which will make this dialog box appear:

The “Create User” dialog. It has fields for email and password, as well as a drop-down menu displaying “Username-Password-Authentication”.

🛠 Enter an email address and password for the user. The only option for the Connection will be Username-Password-Authentication, so leave it as it is. Make a note of that email address and password — you’ll be using them to log in to the app.

🛠 Click the Create button to create the user. The user’s Details page will appear:

The user’s “Details” page.

That takes care of all the setup you need to do within the Auth0 dashboard. It’s time to go back to Xcode and the app.

Add Authentication

With all that setup complete, it’s time to return to coding. In this step, we’ll convert the app into one that uses Auth0 to log the user in and out.

Import the Auth0 library

🛠 Find this line near the beginning of ContentView...

import SwiftUI

...and add this import statement immediately after it:

import Auth0

This addition will allow the app to use the Auth0 object and its methods and properties.

Update the login() method

The login() method merely simulates the login process. Let’s make it real.

🛠 Open ContentView and replace the current login() method with this one:

  func login() {
    Auth0 // 1
      .webAuth() // 2
      .start { result in // 3
        switch result {
          // 4
          case .failure(let error):
            print("Failed with: \(error)")
          // 5
          case .success(let credentials):
            self.isAuthenticated = true
            print("Credentials: \(credentials)")
            print("ID token: \(credentials.idToken)")
        } 
      }
  }

The notes below correspond to the numbered comments in the login() method:

  1. The Auth0 package’s Auth0 object provides methods for the authentication process. Many of these methods perform one of the necessary steps for authentication, and you can chain these methods together to do different authentication tasks.
  2. webAuth() is the first method in the chain. It creates a WebAuth object, which initiates Universal Login. It required the tenant’s domain and app’s client ID, which it collects from the Auth0 property list.
  3. start() is the method that presents the login box. It takes a closure whose sole parameter represents the result of the user’s attempt to log in. The two possible outcomes — a failed login and a successful login — are handled within the closure.
  4. We’re keeping things simple in the failure case. In the case of an unsuccessful login, the app simply prints an error message in the debug console.
  5. If the user successfully logs in, two things happen:
    • The app receives the user’s credentials, a collection of information about the user. One of these credentials is the ID token, which is proof that the user has been authenticated. For now, the app will simply use credentialsidToken property to print the ID token to the debug console; in a later revision, it will extract the user’s name, email address, and picture URL from the token.
    • The isAuthenticated state variable is set to true, and this change causes the UI to update to the “logged in” view.

Update the logout() method

Just as you did with login(), it’s time to give the logout() method real functionality.

🛠 Replace the current logout() method with this one:

  func logout() {
    Auth0 // 1
      .webAuth() // 2
      .clearSession { result in // 3
        switch result {
          // 4
          case .failure(let error):
            print("Failed with: \(error)")
            // 5
          case .success:
            self.isAuthenticated = false
        }
      }
  }

The notes below correspond to the numbered comments in the logout() method:

  1. We’re chaining methods from the Auth0 object again.
  2. Just as with login(), webAuth() is the first method in the chain, and once again, we’re using it to activate Universal Login.
  3. clearSession() does the actual work of logging out. Like the start() method in login(), clearSession() takes a closure with a single parameter that represents the result of that request.
  4. As with login(), the app just prints an error message if the system can’t log the user out.
  5. If the user successfully logs out, the isAuthenticated state variable is set to false, and this change causes the UI to update to the “logged out” view.

Test the updated app

🛠 Run the app to confirm that the app actually authenticates users. This time, when you press the Log in button, instead of going directly to the “logged in” view, you’ll see the Universal Login screen. You’ll need to enter a valid username and password to see that second screen.

Look at Xcode’s debug window after you log in. You’ll see the output of the login() method’s print() functions, which output the contents of the credentials object and its idToken property:

Credentials: Credentials(accessToken: "<REDACTED>", tokenType: "Bearer", idToken: "<REDACTED>", refreshToken: nil, expiresIn: 2022-03-20 04:38:25 +0000, scope: Optional("openid profile email"), recoveryCode: nil)
ID token: eyJhbGciOiJSUzI1NiIsInR5cC...

Note that when the print() function is used to output the contents of credentials, the values of the accessToken and idToken properties are replaced with the string <REDACTED>. Ideally, you should remove print() functions from an app when it goes into production, but many developers often forget this step. Malicious parties can use tools to capture the output of print() functions from production apps; this is why Credentials instances redact the values of their accessToken and idToken properties when printed.

credentials has a scope property containing a space-delimited list of OpenID Connect (OIDC) scopes — authorizations for access to details about the user — that Auth0 has granted to the app. Unless you specify otherwise, Auth0.swift defaults to requesting the following scopes when logging in a user:

  • openid: Authorization to use OIDC to verify the user's identity
  • profile: Authorization to access the user’s name information
  • email: Authorization to access the user’s email address

To confirm that the app received an ID token after logging in the user, we print its value. We’ll use it to get the user’s name, email address, and picture in the next step.

🚨 Warning: 🚨 It’s fine to print the value of the ID token to the debug console while you’re learning about the authentication process or building the app. Make sure that you remove print() statements — especially those that print sensitive information, such as the ID token — before putting them into production!

So far, you’ve created a SwiftUI-based iOS app that uses Auth0 for basic login and logout functionality. In the second part of this tutorial, you’ll give the app the ability to get information about the logged-in user and display it onscreen.

  • Twitter icon
  • LinkedIn icon
  • Faceboook icon