---
title: "Get Started with iOS Authentication using SwiftUI, Part 2: User Info, ID Tokens, and JWTs"
description: "Add personalization to your iOS/SwiftUI app with user info from the ID token, a JWT (JSON Web Token) that you’ll read with the Swift JWTDecode library."
authors:
  - name: "Joey deVilla"
    url: "https://auth0.com/blog/authors/joey-devilla/"
  - name: "Peter Fernandez"
    url: "https://auth0.com/blog/authors/peter-fernandez/"
date: "Jul 26, 2024"
category: "Developers,Tutorial,iOS"
tags: ["mobile", "authentication", "native"]
url: "https://auth0.com/blog/get-started-ios-authentication-swift-swiftui-part-2-user-profiles/"
---

# Get Started with iOS Authentication using SwiftUI, Part 2: User Info, ID Tokens, and JWTs

In Part 1 of this tutorial, you created a SwiftUI-based iOS app that uses Auth0 for basic login and logout functionality. In this part, you’ll enhance your app by giving it the ability to read the user’s profile to display their photo, name, and email address when they’re logged in.

<include 
    src="LinkCard" 
    title="Calling a Protected API from an iOS Swift App" 
    link="https://auth0.com/blog/calling-protected-apis-from-ios-swift/" 
    description="Looking for a step-by-step guide to leveraging OAuth 2.0 when accessing protected APIs via an iOS app built with Swift? If you're integrating with Auth0, then this is everything you need to know!"     img="https://images.ctfassets.net/23aumh6u8s0i/5PC3nu1F68m8S3BmJFv9SN/e83487c6d89d72fb6a49155722959b1d/ios_hero_2021_2.jpeg"
/>

Once again, you can follow the text in this article, or if you prefer learning by video, you can follow the steps in this article’s companion video:

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

> Look for the 🛠 emoji if you’d like to skim through the content while focusing on the build and execution steps.
> 
> The 📺 emoji highlights links to specific points in the video.


## Examine the ID Token

📺 [The _Examine the ID Token_ section of the video](https://www.youtube.com/watch?v=xOBoLegDmTw&t=2008s)
 
If you look at the `.success` case of the `switch` statement in `ContentView`’s `login()` method, you’ll see these `print()` functions:

```swift
print("Credentials: \(credentials)")
print("ID token: \(credentials.idToken)")
```

These functions’ output will appear in Xcode’s Debug area:

![Xcode screenshot highlighting the Debug area.](https://images.ctfassets.net/23aumh6u8s0i/2Odv2P2CeeMGBoKSHNl3ly/2ba5ae37dbc5afafb94e82f95f41a722/debug_area.png)

> If the Debug area isn’t visible, open the _View_ menu and select _Debug Area_ → _Show Debug Area_ or use the keyboard shortcut _command-Shift-Y_.

You’ll see the contents of the `credentials` object and its `idToken` property, which should look similar to this:

```
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...
```

The `credentials` object is a package of information that Auth0 sends to your app after authenticating a user. This information includes:

- **ID token:** Data that proves that the user has been authenticated.
- **Access token:** Data that gives a client application permission to access a specific resource to perform specific actions on the user’s behalf.
- **Refresh token:** Applications use this to get additional access tokens when the original access token expires without requiring the user to re-authenticate.
- **Scopes:** A set of [OpenID Connect (OIDC) scopes](https://auth0.com/docs/get-started/apis/scopes/openid-connect-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

> Want to know more about ID tokens and access tokens? We explain all in our article, [_ID Token and Access Token: What's the Difference?_](https://auth0.com/blog/id-token-access-token-what-is-the-difference/)
> 
> Want to know more about refresh tokens? See our article, [_What Are Refresh Tokens and How to Use Them Securely_](https://auth0.com/blog/refresh-tokens-what-are-they-and-when-to-use-them/).

The piece of information that we’re most interested in (for this exercise) is the ID token.

When the `print()` function is used to output the contents of `credentials`, the values of the `idToken` and `accessToken` properties are replaced with the string `<REDACTED>` as a security measure. 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 `idToken` and `accessToken` properties when printed.

Note that when we use the `print()` function to output `credentials.idToken` — the ID token itself — the value is _not_ redacted. That’s because this value is useful for debugging, which we’ll do in the next step.

> 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 you remove `print()` statements — especially those that print sensitive information, such as the ID token — before putting them into production!


### What’s in the ID token?

📺 [The _What’s in the ID token?_ section of the video](https://www.youtube.com/watch?v=xOBoLegDmTw&t=2118s)

To see what’s in the ID token, copy its value from the Debug area, go to Auth0’s [JWT.io site](https://jwt.io/) and paste that value into the _Encoded_ text area on the left side of the page. JWT.io will decode the ID token from its JWT form and display its decoded contents in the _Decoded_ area on the page’s right side:

![JWT.io and the decoded ID token.](https://images.ctfassets.net/23aumh6u8s0i/4sg6VirydfCzVVenH6LWil/174552abed55b4fe3d8100493c1510db/jwt.io_screenshot.png)

In the _Decoded_ area’s _Payload_ section, you’ll see the decoded user information from the ID token, including the data that we want the app to display: the user’s name, email address, and picture.

In the next step, we’ll give the app the same ID token-decoding capability as JWT.io’s.

> Auth0 has plenty of information about JWTs. In addition to the main [JWT.io page](https://jwt.io/), you should visit JWT.io’s [_Introduction to JSON Web Tokens_](https://jwt.io/introduction) and download our [free JWT Handbook](https://auth0.com/resources/ebooks/jwt-handbook).


## Get the User’s Information

📺 [The _Get the User’s Information_ section of the video](https://www.youtube.com/watch?v=xOBoLegDmTw&t=2223s)

The app only “knows” whether the user is logged in or logged out in its current state. It also has information about the user’s identity encoded in the ID token. Let’s extract this user information — the *user profile* — and use it to display the user’s name, email address, and picture when the user is logged in. 

🛠 In `Profile`, add the following `import` statement before the `struct Profile` line:

```Swift
// [ 📄 Profile.swift ]

import JWTDecode

// [ More code here ]
```

🛠 In the `Profile` extension, replace the `// TODO: Implement the 'from()' method.` comment with this `from()` method. It uses a couple of methods from the newly-imported `JWTDecode` library:

```swift
// [ 📄 Profile.swift ]

// [ More code here ]

  static func from(_ idToken: String) -> Self {
    guard
      let jwt = try? decode(jwt: idToken),
      let id = jwt.subject,
      let name = jwt.claim(name: "name").string,
      let email = jwt.claim(name: "email").string,
      let emailVerified = jwt.claim(name: "email_verified").boolean,
      let picture = jwt.claim(name: "picture").string,
      let updatedAt = jwt.claim(name: "updated_at").string
    else {
      return .empty
    }

    return Profile(
      id: id,
      name: name,
      email: email,
      emailVerified: String(describing: emailVerified),
      picture: picture,
      updatedAt: updatedAt
    )
  }
  
// [ More code here ]
```

Given an ID token string, the `from()` function creates a `Profile` instance. If `from()` can extract claims — values about the user’s identity, which include their name, email address, and the URL for their picture — from the ID token, it returns a `Profile` instance with that information in its properties. Otherwise, it returns a `Profile` instance with empty properties.


## Display the User’s Information

📺 [The _Display the User’s Information_ section of the video](https://www.youtube.com/watch?v=xOBoLegDmTw&t=2424s)

Now that there’s a way to extract information from an ID token, let’s put it to use. 

Since `userProfile` is marked with the `@State` attribute, it defines the user interface’s state. Whenever `userProfile` or one of its properties changes, the app redraws the user interface to reflect the change.

We want to display the user’s information when they log in, so we’ll use `Profile`’s newly-created `from()` method in the `login()` method.

🛠 Open `ContentView` and update `login()` as shown below:

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

// [ More code here ]

  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
            // 👇🏽👇🏽👇🏽 New line of code here!
            self.userProfile = Profile.from(credentials.idToken)
            // 👆🏽👆🏽👆🏽
            print("Credentials: \(credentials)")
            print("ID token: \(credentials.idToken)")
        }
      }
  }

// [ More code here ]
```

The newly-added line of code runs after the user logs in, and the app receives the ID token. It creates a new `Profile` instance from the data in the ID token and sets `ContentView`’s `userProfile` property to that instance.

When the user logs out, we should clean up the user profile just to be safe.

🛠 Update `logout()` as shown below:

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

// [ More code here ]

  func logout() {
    Auth0
      .webAuth()
      .clearSession { result in
        switch result {
          case .success:
            self.isAuthenticated = false
            // 👇🏽👇🏽👇🏽 New line of code here!
            self.userProfile = Profile.empty
            // 👆🏽👆🏽👆🏽

          case .failure(let error):
            print("Failed with: \(error)")
        }
      }
  }

// [ More code here ]
```


## Run the App Again

📺 [The _Run the App Again_ section of the video](https://www.youtube.com/watch?v=xOBoLegDmTw&t=2566s)

Run the app and confirm that the changes work. When you log in, you should see the user’s name, email address, and picture:

![The app’s “logged in” screen, featuring the text “Logged in” and displaying the user’s picture, name, and email address.](https://images.ctfassets.net/23aumh6u8s0i/1zYLUYAU3fdbLLde9PmhCN/90854331950e7557fbcc52db5bcb7379/logged_in_screen.png)

Congratulations, and high-fives and handshakes all around! You’ve taken a SwiftUI app and given it the ability to authenticate users with Auth0.


## Next Steps

SwiftUI is an expansive topic; we only scratched its surface in this tutorial. For your next steps in exploring it, you might want to look at these valuable resources:

- [SwiftUI by Example](https://www.hackingwithswift.com/quick-start/swiftui)
- [Your First SwiftUI App](https://www.youtube.com/watch?v=VlhcNR7Qrno)
- [Stanford University’s “Developing Applications for iOS” course for Spring 2021](https://www.youtube.com/playlist?list=PLpGHT1n4-mAsxuRxVPv7kj4-dQYoC3VVu)

📺 Last but not least, the video ends with [closing remarks and a quick accordion number](https://www.youtube.com/watch?v=xOBoLegDmTw&t=2645s)!