iOS Swift: User Sessions

View on Github

iOS Swift: User Sessions

Gravatar for martin.walsh@auth0.com
By Martin Walsh
Auth0

This tutorial will show you how to handle user sessions and retrieve the user's profile. We recommend you to Log in to follow this quickstart with examples configured for your account.

I want to explore a sample app

2 minutes

Get a sample configured with your account settings or check it on Github.

View on Github
System requirements: CocoaPods 1.2.1 | Version 8.3.2 (8E2002) | iPhone 7 - iOS 10.3 (14E269)

Credentials Manager

This guide shows you how to use the credentials manager to store and Refresh Tokens.

Auth0.swift provides a utility class to streamline the process of storing and renewing credentials. You can access the accessToken or idToken properties from the Credentials instance.

You can also use SimpleKeychain directly, without the added benefits and convenience of the credentials manager. To learn more, read about Saving and Refreshing Tokens.

Save the User's Credentials When They Log in

When your users log in successfully, save their credentials. You can then log them in automatically when they open your application again.

To get a Refresh Token during authentication, use the offline_access scope. You can use the Refresh Token to request a new Access Token when the previous one expires.

First, import the Auth0 module to the file that will present the login page:

import Auth0

Next, present the login page:

// HomeViewController.swift
Credentials manager
// Create an instance of the credentials manager for storing credentials
let credentialsManager = CredentialsManager(authentication: Auth0.authentication())

Auth0
    .webAuth()
    .scope("openid profile offline_access")
    .audience("https://YOUR_AUTH0_DOMAIN/userinfo")
    .start {
        switch $0 {
        case .failure(let error):
            // Handle the error
            print("Error: \(error)")
        case .success(let credentials):
            // Auth0 will automatically dismiss the login page
            // Store the credentials
            credentialsManager.store(credentials: credentials)
        }
}

Check for Credentials When the User Opens Your Application

When the user opens your application, check for valid credentials. If they exist, you can log the user in automatically and redirect them to the app's main flow without any additional login steps.

We recommend that you download the sample project from this tutorial and take a look at its implementation. Focus on the CredentialsManager class, which manages session handling, obtains user credentials and saves them.

First, you check if the credentials manager has valid credentials:

// SessionManager.swift

guard credentialsManager.hasValid() else {
    // No valid credentials exist, present the login page
}

Next, retrieve the credentials:

// SessionManager.swift

credentialsManager.credentials { error, credentials in
    guard error == nil, let credentials = credentials else {
        // Handle error
        print("Error: \(error)")
    }
    // You now have a valid credentials object, you might want to store this locally for easy access.
    // You will use this later to retrieve the user's profile
} 

If the credentials have expired, the credentials manager will automatically renew them for you with the Refresh Token.

Clear the Keychain When the User Logs Out

When you need to log the user out, remove their credentials from the keychain:

// SessionManager.swift

credentialsManager.clear()

Retrieve the User Profile

To get the user's profile, you need a valid Access Token. You can find the token in the credentials object returned by the credentials manager.

// SessionManager.swift

// credentials = A returned credentials object from the credentials manager in the previous step.

guard let accessToken = credentials?.accessToken
    else { // Handle Error }
Auth0
    .authentication()
    .userInfo(withAccessToken: accessToken)
    .start { result in
        switch(result) {
        case .success(let profile):
            // You've got the user's profile, good time to store it locally.
            // e.g. self.profile = profile
        case .failure(let error):
            // Handle the error
            print("Error: \(error)")
        }
    }

User Profile Information

To show the information contained in the user profile, access its properties, for example:

// ProfileViewController.swift

if let name = profile.name, let pictureURL = profile.picture {
  // Show Information
}

Read the UserInfo class documentation to learn more about its properties.

Managing Metadata

You can request more information than returned in the basic profile. To do this, you will be accessing the Auth0 Management API.

Additional scopes

You will need to update the original login scopes to include read:current_user to gain access to the full profile data and update:current_user_metadata to gain access to patch this data.

Audience

You will also need to change your audience to the API Audience identifier for the Management API. The default identifier is https://YOUR_AUTH0_DOMAIN/api/v2/

Login

Putting this all together you should have a login that looks like:

// HomeViewController.swift

Auth0
    .webAuth()
    .scope("openid profile offline_access read:current_user update:current_user_metadata")
    .audience("https://YOUR_AUTH0_DOMAIN/api/v2/")
    .start {
        switch $0 {
        case .failure(let error):
            // Handle the error
            print("Error: \(error)")
        case .success(let credentials):
            // Auth0 will automatically dismiss the login page
            // Store the credentials
            credentialsManager.store(credentials: credentials)
        }
}

Patch User Metadata

You can add custom user information in the user metadata section by performing a patch:

let accessToken = ... // You will need the accessToken from your credentials instance 'credentials.accessToken'
let profile = ... // the Profile instance you obtained accessing the `/userinfo` endpoint.
Auth0
    .users(token: idToken)
    .patch(profile.sub, userMetadata: ["country": "United Kingdom"])
    .start { result in
        switch result {
          case .success(let user):
              // Patch Successful
              // user is a fresh copy of the full profile which includes your changes
          case .failure(let error):
              // Deal with failure
        }
}

Retrieve User Metadata

The user_metadata dictionary contains fields related to the user profile. You can specify the fields you want to retrieve, or use an empty array [] to pull back the full user profile.

Retrieving the user_metadata dictionary:

let accessToken = ... // You will need the accessToken from your credentials instance 'credentials.accessToken'
let profile = ... // the Profile instance you obtained accessing the `/userinfo` endpoint.
Auth0
    .users(token: idToken)
    .get(profile.sub, fields: ["user_metadata"], include: true)
    .start { result in
        switch result {
        case .success(let user):
            guard let userMetadata = user["user_metadata"] as? [String: Any] else { return }
            // Access userMetadata
        case .failure(let error):
            // Deal with failure
        }
}

Accessing the user's metadata. You can choose the key names and set the appropriate type for the user_metadata dictionary data.

let country = userMetadata["country"] as? String
Use Auth0 for FREE