---
title: "ChatGPT Tries to Add Auth0 Authentication to an iOS App, Round Two!"
description: "We asked ChatGPT to write code to integrate Auth0 into an iOS app after its initial release. The code didn’t work then. Will it work this time?"
authors:
  - name: "Joey deVilla"
    url: "https://auth0.com/blog/authors/joey-devilla/"
date: "Jul 17, 2023"
category: "Developers,Tutorial,iOS"
tags: ["mobile", "authentication", "swift", "chatgpt"]
url: "https://auth0.com/blog/chatgpt-add-auth0-authentication-ios-round-2/"
---

# ChatGPT Tries to Add Auth0 Authentication to an iOS App, Round Two!

## What Happened in Round One

Barely two weeks after the initial release of ChatGPT, I tidied up my home office/studio, put on my newest Aloha shirt, and started asking the newly-released AI some questions about OAuth and Auth0. The result was the video below, which you’ll find on the OktaDev YouTube channel: _Chatting with ChatGPT About Auth0:_

<iframe width="600" height="338" src="https://www.youtube.com/embed/rfkgdorO-8Y" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen></iframe>

ChatGPT gave correct answers to these questions:

- “What is OAuth?” and a follow-up question where I asked it for a more layperson-friendly version of its initial answer.
- “What is OIDC?” and the same follow-up question as my previous one.
- What is an ID token?
- What is an access token?
- What is a refresh token?
- Are there security downsides to using refresh tokens with indefinite lifespans?

ChatGPT didn’t do as well when I asked it, “How do I write an iOS app that uses Auth0 for login?” The set of steps it suggested was correct, but it said that I should use the  `Auth0.authentication()` method to make the Universal Login screen appear. **No such method exists**.


## And Now, Round Two! 

Half a year has passed since I asked ChatGPT about adding Auth0 authentication to an iOS app. Over that period, OpenAI’s developers added a newer model, GPT 4.0, which you can access only if you have a paid account. They also made adjustments and improvements to the original GPT 3.5 model, which powers the free version of ChatGPT.

I decided to see if the free version of ChatGPT could give me a working iOS authentication code this time. I asked it **“How do I write an iOS app that uses Auth0 for login and logout?”**

Here’s ChatGPT’s response, which I’ve condensed slightly for brevity:

1. Set up an Auth0 account.
2. Create an iOS project. Set it up with the desired UI and navigation flow for the login and logout functionality.
3. Install the Auth0 SDK. You can use CocoaPods or Swift Package Manager to install the SDK dependencies.
4. Configure your Auth0 application by providing the necessary settings, such as allowed callback URLs and logout URLs.
5. Implement login functionality: Create a login view controller or integrate the login functionality into an existing view controller. Use the Auth0 SDK to initiate the login process by presenting the Auth0 login screen. The user will be able to enter their credentials or choose a social login option.
6. Handle login callback: Once the user successfully logs in, Auth0 will redirect them back to your app. You need to implement the callback handling in your app to receive the authentication result. This typically involves handling a URL scheme or Universal Link that Auth0 uses to redirect back to your app.
7. Store and manage tokens: When the login is successful, Auth0 provides an access token and, optionally, a refresh token. You'll need to store these tokens securely, such as using the iOS Keychain, and handle token refreshing when necessary.
8. Implement logout functionality: Create a logout function that clears the stored tokens and logs out the user. You can use the Auth0 SDK to perform the logout operation.
9. Secure API requests: To secure your app's API requests, include the access token in the authorization header when making requests to your backend services. Ensure that your backend verifies the authenticity of the token with Auth0.
10. Test and refine: Thoroughly test your app's login and logout functionality to ensure it works as expected. Make any necessary refinements or enhancements based on user experience and feedback.

I then asked **“Could you show me some Swift code that uses Auth0 for login and logout?”**

Its response: “Certainly! Here's an example of Swift code that demonstrates how to use Auth0 for login and logout in an iOS app,” followed by this code:

```swift
import Auth0

class Auth0Manager {
    let auth0 = Auth0.webAuth(clientId: "YOUR_CLIENT_ID", domain: "YOUR_DOMAIN")

    func login(completion: @escaping (Error?) -> Void) {
        auth0
            .scope("openid profile")
            .audience("https://YOUR_API_IDENTIFIER")
            .start { result in
                switch result {
                case .success(let credentials):
                    // Successful login
                    let accessToken = credentials.accessToken
                    let idToken = credentials.idToken
                    // Store the tokens securely

                    completion(nil)

                case .failure(let error):
                    // Handle error
                    completion(error)
                }
            }
    }

    func logout() {
        auth0.clearSession(federated: true) { result in
            switch result {
            case .success:
                // Successful logout
                // Clear stored tokens and any other user data

            case .failure(let error):
                // Handle error
                print("Logout error: \(error)")
            }
        }
    }
}
```

My thought was probably what you’re thinking right now: _Does this code work?_

I opened a copy of the iOS project I use for demonstrating Auth0 authentication, which is based on the Auth0 iOS Quickstart app (you can [download a version configured with your Auth0 tenant settings](https://auth0.com/docs/quickstart/native/ios-swift/01-login) or [get it from this Github repository](https://github.com/auth0-samples/auth0-ios-swift-sample/tree/master/Sample-01)). I added a new file to the project, `Auth0Manager.swift`, and pasted the class that ChatGPT generated there. I replaced these placeholder values...

- `YOUR_CLIENT_ID` with my app’s client ID
- `YOUR_DOMAIN`with my tenant’s domain
- `YOUR_API_IDENTIFIER` with `https://YOUR_DOMAIN/api/v2/`, replacing `YOUR_DOMAIN` with my tenant’s domain

…and replaced my demo app’s calls to its original `login()` and `logout()` methods with calls to the versions that ChatGPT provided.

I ran the app...

...and it worked! It appears that this time, ChatGPT — and the _free_ version at that — got it right.


## A Closer Look At ChatGPT’s Code

Now that it’s clear that ChatGPT now knows how to write code to integrate Auth0 into an iOS app let’s take a look at the way it did this.

<img src="https://images.ctfassets.net/23aumh6u8s0i/2g2IgpFO8E6hNzFAwaDfdc/e2042210acd1c1b96f3c4629001a5d39/gavel.png" align="left" style="padding: 20px;" alt="Judge’s gavel resting on a hardcover book." />To make this exercise a little more fun, I’ll keep a running score where I’ll award points for what I thought were good things that ChatGPT did and deduct points for things that I thought were bad ones. Watch for the picture of the gavel for these scores.


### The Auth0Manager class

This is different from a lot of [tutorial code](https://auth0.com/blog/get-started-ios-authentication-swift-uikit/), which puts the Auth0 logic and data — the`login()` and `logout()` methods as well as the variables to hold the tokens that Auth0 returns —  inside the view object that makes the call to display the Universal Login screen or log the user out. Many tutorials take this approach because it shows all the code in a single file, which is useful when you’re trying to explain something new to the reader.

In a _real_ iOS app (as opposed to a tutorial app), you’d probably take the same approach as ChatGPT’s and put the authentication and authorization code in its own class. In fact, [that’s what we do in tutorials showing how to integrate Auth0 into Android apps](https://auth0.com/blog/add-progressive-profiling-auth0-authentication-android-apps-jetpack-compose/) since they rely heavily on ViewModels that inherit from Android’s built-in `ViewModel` class.

<img src="https://images.ctfassets.net/23aumh6u8s0i/2g2IgpFO8E6hNzFAwaDfdc/e2042210acd1c1b96f3c4629001a5d39/gavel.png" align="left" style="padding: 20px;" alt="Judge’s gavel resting on a hardcover book." />I’ve decided to follow ChatGPT’s example and put Auth0 code in its own class in my tutorials from now on to make my tutorial code a little closer to real-world code. For this idea, I’ll award ChatGPT 1 point.


### The WebAuth instance

ChatGPT’s `Auth0Manager` class has a single property, `auth0`, a `WebAuth` instance whose definition is as follows:

```swift
let auth0 = Auth0.webAuth(clientId: "YOUR_CLIENT_ID", domain: "YOUR_DOMAIN")
```

`Auth0.webAuth()` is a function in the _Auth0.Swift_ library that creates an instance of the `WebAuth` class, which provides the necessary methods for logging a user in and out. Both the `login()` and `logout()` methods use this instance.

ChatGPT’s solution uses the version of `Auth0.webAuth()` that takes two arguments: the client ID and the domain. It’s the most straightforward way to show how you can use Auth0 to implement login and logout in an app, but you probably wouldn’t do this in a production application since you’d be hard-coding server credentials.

Fortunately, there’s another form of `Auth0.webAuth()` that _doesn’t_ take arguments for the client ID and domain. In fact, it doesn’t take _any_ arguments, and you’d use it like this:

```swift
let auth0 = Auth0.webAuth()
```

Instead of relying on arguments that you pass to it, this form of `Auth0.webAuth()` looks through the app’s property lists (a.k.a. _plists_) for values corresponding to the following keys:

- `ClientId` for the client ID
- `Domain` for the tenant domain

You would typically create a new property list — usually named `Auth0.xml` — and store the `ClientID` and `Domain` values there. Here’s what it would look like in an Xcode project if you prefer editing property lists visually...

![auth0_plist](https://images.ctfassets.net/23aumh6u8s0i/6LexUyPkhqCzEvMCASpR37/246ed1182fd7d410cebaca9c4a6d01b0/auth0_plist.png)

...and here’s how it would look if you prefer editing property lists as source code:

```xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>Domain</key>
    <string>** Put your tenant’s domain here ***</string>
    <key>ClientId</key>
    <string>** Put your app’s client ID here ***</string>
</dict>
</plist>
```

Putting the client ID and domain values in their own file makes it easy to exclude them from version control, which makes it less likely that you’ll unintentionally share these values with people outside your organization.

<img src="https://images.ctfassets.net/23aumh6u8s0i/2g2IgpFO8E6hNzFAwaDfdc/e2042210acd1c1b96f3c4629001a5d39/gavel.png" align="left" style="padding: 20px;" alt="Judge’s gavel resting on a hardcover book." />ChatGPT’s implementation works when trying to explain how to implement something, which earns it 1 point. However, its implementation isn’t one that you should use in a production application, and it should have explained this fact, so I’m deducting the point I just gave it. ChatGPT’s current score is holding at 1 point.


### The login() method

Let’s take a look at ChatGPT’s `login()` method:

```swift
func login(completion: @escaping (Error?) -> Void) {
    auth0
        .scope("openid profile")
        .audience("https://YOUR_API_IDENTIFIER")
        .start { result in
            switch result {
            case .success(let credentials):
                // Successful login
                let accessToken = credentials.accessToken
                let idToken = credentials.idToken
                // Store the tokens securely

                completion(nil)

            case .failure(let error):
                // Handle error
                completion(error)
            }
        }
}
```

Its `login()` implementation is mostly the same as the `login()` methods in our tutorials or our iOS Quickstart app. There’s the usual method chaining from the `webAuth` instance, where the methods are called in this order:

- `scope()` to request the minimum amount of scopes necessary to authenticate a user:
    -   `openid` to indicate that we want to use OpenID Connect (OIDC) to verify the user’s identity. Since Auth0 authentication is OIDC-based, Any application using Auth0 must request this scope.
    -  `profile` to retrieve the user’s name.
    -  The ChatGPT code doesn’t include a request for the `email` scope, which I would recommend, simply for access to the user’s email address, which is typically how an app would send out-of-band communications to the user.
-  `audience()` to specify one or more APIs that the access token that Auth0 returns should grant access to. In the rare case that you’re using Auth0 for authentication only, you can skip this method call. In my case, I passed it the string `https://MY_DOMAIN/api/v2/`, replacing `MY_DOMAIN` with my tenant’s domain. This is the URL for the Auth0 user management API, which is useful for accessing the user’s app and user metadata.
- `start()` to indicate what the app should do in the cases where the user was able to log in and where they weren’t.

The big difference between ChatGPT’s implementation of `login()` and the ones we’ve been using here on the Auth0 blog and in our Quickstarts can be seen in the `login()` method’s signature:

```swift
func login(completion: @escaping (Error?) -> Void)
```

ChatGPT’s version of `login()` has a parameter, `completion`, that takes an argument of type `(Error?) -> Void`. This argument is a closure that takes an argument of type `Error?` (a value whose type is `Error`, a subclass of `Error`, or `nil`) and does not return a value. The `@escaping` annotation informs Swift that the closure provided to `login()` might [outlive or go beyond `login()`’s scope](https://www.donnywals.com/what-is-escaping-in-swift/).

The `completion` parameter allows the code that calls `login()` to perform additional actions upon successful login and also in case login fails:

- If the user logged in successfully, `login()` calls `completion(nil)`.
- If the user’s attempt to log in failed, `login()` calls `completion(error)`, where `error` is the `Error` instance returned by `start()` method of the `WebAuth` instance contained in the `auth0` property.

The code calling `login()` must provide a closure argument that specifies what extra actions should happen whether the login succeeds or fails. For example, here’s the code in my demo app that calls `Auth0NManager`’s `login()` method:

```swift
auth0Manager.login() { error in
    if let error = error {
        print("Login error!")
        isAuthenticated = false
    } else {
        print("Login successful!")
        isAuthenticated = true
    }
}
```

<img src="https://images.ctfassets.net/23aumh6u8s0i/2g2IgpFO8E6hNzFAwaDfdc/e2042210acd1c1b96f3c4629001a5d39/gavel.png" align="left" style="padding: 20px;" alt="Judge’s gavel resting on a hardcover book." />I like ChatGPT’s addition of the <code>completion</code> parameter and feel no shame in stealing this idea (is it even possible to steal from an AI?). I’m granting ChatGPT 1 point, resulting in a total of 2 points so far.


### The logout() method

Here’s ChatGPT’s `logout()` method:

```swift
func logout() {
    auth0.clearSession(federated: true) { result in
        switch result {
        case .success:
            // Successful logout
            // Clear stored tokens and any other user data
            print("Logged out!")
            
        case .failure(let error):
            // Handle error
            print("Logout error: \(error)")
        }
    }
}
```

ChatGPT’s implementation of the `logout()` method is pretty much the same as the `logout()` methods in our tutorials or our iOS Quickstart app.

I would steal ChatGPT’s trick from its `login()` method and add a `completion` parameter that takes a closure that performs additional actions for both successful and unsuccessful logouts. My implementation would look something like this:

```swift
func logout(completion: @escaping (Error?) -> Void) {
    auth0.clearSession(federated: true) { result in
        switch result {
        case .success:
            // Successful logout
            // Clear stored tokens and any other user data
            completion(nil)
            
        case .failure(let error):
            // Handle error
            completion(error)
        }
    }
}
```

And here’s how I’d call the `logout()` method:

```swift
auth0Manager.logout() { error in
    if let error = error {
        print("Logout error!")
    } else {
        print("OK")
        isAuthenticated = false
    }
}
```

<img src="https://images.ctfassets.net/23aumh6u8s0i/2g2IgpFO8E6hNzFAwaDfdc/e2042210acd1c1b96f3c4629001a5d39/gavel.png" align="left" style="padding: 20px;" alt="Judge’s gavel resting on a hardcover book." />ChatGPT didn’t provide a <code>completion</code> parameter for the <code>logout()</code> method as it did for the <code>login()</code> method. I won’t award it a point, but I won’t take one away, either. At the end of this exercise, ChatGPT has 2 points. Not bad!


## Is Your Developer Job Safe?

Considering that it’s been only half a year since we last tested ChatGPT’s ability to write code that integrates Auth0 into iOS apps, this is an impressive improvement. You might be wondering what kinds of leaps it might make over the next couple of years if AIs keep advancing at the same pace, and more importantly, what this means for your career as a developer.

I don’t think of AIs like ChatGPT as a threat. Instead, I think of them as part of a long series of cognitive aids that include  [tally sticks](https://en.wikipedia.org/wiki/Tally_stick), [the abacus](https://www.ecb.torontomu.ca/~elf/abacus/intro.html), writing, [logarithmic tables](https://www.cuemath.com/algebra/log-table/), and [slide rules](https://sliderulemuseum.com/SR_Course.htm), as well as their more modern counterparts such as the combination of search engines and Stack Overflow, [code completion](https://en.wikipedia.org/wiki/Intelligent_code_completion), and [GitHub Copilot](https://github.com/features/copilot). I think that AIs can enhance what a human programmer can do and even provide ideas and inspiration that they might not think of. After all, ChatGPT’s answer provided me with a couple of ideas that I’m going to use in future code.

You might find it helpful to read this IEEE Spectrum article, [_How Coders Can Survive—and Thrive—in a ChatGPT World_](https://spectrum.ieee.org/ai-programming), which lists four ways in which developers can stay ahead of generative AIs. It captures my thinking about AI and programming in its final paragraph:

<blockquote>For programmers to survive in a generative AI world, they’ll need to embrace AI as a tool and incorporate AI into their workflow while recognizing the opportunities and limitations of these tools—and still relying on their human coding capabilities to thrive.</blockquote>