FIDO2

Introduction

This guide explains how to implement the FIDO2 registration and authentication workflow on iOS applications. You’ll find a detailed introduction about FIDO2 in our FIDO2 guide.

The following code samples and screenshots are issued from our example application using our SDK. Feel free to check out the Github project.

FIDO2 Prerequisites

To successfully enable FIDO2:

  1. Enable the WebAuthn feature on your ReachFive account.

    You may need to contact support to have this enabled if you do not see it on your ReachFive Console.
  2. From your ReachFive console:

    1. Navigate to Settings > WebAuthn.

    2. Configure the following:

      console webauthn settings
      1. Application name: the name of the application that is displayed to the user during the FIDO2 Registration or Authentication process. There are no particular restrictions on what you can use here.

      2. Allowed origins: the list of URLs that are allowed to make calls to the API endpoints provided by ReachFive to perform the FIDO2 Registration or Authentication process.

You also need
  • An iOS device with a fingerprint sensor or a configured screen lock.

  • iOS Mobile OS 13.3 or later.

    Make sure to register a fingerprint (or screenlock).

Signup

The user requests to register a new account for the first time. Users don’t need to provide a password, but instead provide an identifier like an email or mobile number as well as some personal data.

Subsection

Jump to the signup process

Here is a snapshot of the signup view displayed to the user.

webauthn signup

Signup process

The signupWithWebAuthn method initiates the FIDO2 signup process to retrieve a randomly generated challenge, the Relying Party information, and the user information from the ReachFive server. The options are then passed to the FIDO2 CLIENT which returns an FaceId Dialog to generates a new credential (WebauthnSignupCredential).

Once the UI successfully generates a new credential, it sends the resulting data (which contains the information about this new credential) back to the ReachFive server and finalizes the FIDO2 signup process by returning a one-time authentication token.

Finally, the result of the authentication callback request is parsed and a user’s authentication token is retrieved.

import UIKit
import IdentitySdkCore
import PromiseKit
import CryptoSwift

class SignUpFidoControllerViewController: UIViewController{

    @IBOutlet weak var emailText: UITextField!
    @IBOutlet weak var givenNameText: UITextField!
    @IBOutlet weak var familyNameText: UITextField!
    @IBOutlet weak var deviceNameText: UITextField!

    let scopes = ["openid", "email", "profile", "phone", "full_write", "offline_access"]

    override func viewDidLoad() {
        super.viewDidLoad()
        AppDelegate.reachfive().initialize().onComplete { _ in }
        deviceNameText.text = UIDevice.current.name
    }

    @IBAction func SignupButton(_ sender: Any) {
        let profile = ProfileWebAuthnSignupRequest(
            email: emailText.text,
            givenName: givenNameText.text,
            familyName: familyNameText.text
        )

        AppDelegate
            .reachfive()
            .signupWithWebAuthn(
                profile: profile,
                origin: AppDelegate.origin,
                friendlyName: deviceNameText.text,
                viewController: self,
                scopes: self.scopes
            )
            .onSuccess{ authToken in self.goToProfile(authToken) }
            .onFailure { error in
                var messageAlert = ""

                switch error {
                    case .RequestError(let requestErrors):
                        messageAlert = requestErrors.errorDescription!
                    case .TechnicalError(_, let apiError):
                        messageAlert = (apiError?.errorDescription)! as String
                    default:
                        messageAlert = error.localizedDescription
                }

                let alert = UIAlertController(title: "Error", message:messageAlert, preferredStyle: UIAlertController.Style.alert)
                alert.addAction(UIAlertAction(title: "Dismiss", style: UIAlertAction.Style.default, handler: nil))

                self.present(alert, animated: true, completion: nil)
            }
    }

    func goToProfile(_ authToken: AuthToken) {
        AppDelegate.storage.save(key: AppDelegate.authKey, value: authToken)

        let storyBoard: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
        let profileController = storyBoard.instantiateViewController(
            withIdentifier: "ProfileScene"
        ) as! ProfileController

        profileController.authToken = authToken
        self.self.navigationController?.pushViewController(profileController, animated: true)
    }

    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        view.endEditing(true)
        super.touchesBegan(touches, with: event)
    }
}

Authentication

Once the user has a credential registered on the server and the device, they can use it to easily login with their identifier.

Subsection

Jump to the authentication process

Here is a snapshot of the login view displayed to the user.

webauthn login

Authentication process

The loginWithWebAuthn method initiates the FIDO2 authentication process to retrieve the list of previously registered credentials and a challenge string from the server. This information is passed to the FIDO2 CLIENT which searches for a credential that matches the Relying Party ID and creates an FaceID dialog for the user to consent for authentication (AuthenticationPublicKeyCredential) .

After that the UI successfully retrieves the existing credential, the operation’s result is returned to the ReachFive server and finalizes the FIDO2 authentication process by returning a one-time authentication token.

Finally, the result of the authentication callback request is parsed and the user’s authentication token is retrieved.

import UIKit
import IdentitySdkCore
import PromiseKit
import CryptoSwift

class LoginWithFidoViewController: UIViewController{

    @IBOutlet weak var emailText: UITextField!

    let scopes = ["openid", "email", "profile", "phone", "full_write", "offline_access"]

    override func viewDidLoad() {
        super.viewDidLoad()
        AppDelegate.reachfive().initialize().onComplete { _ in }
    }

    @IBAction func loginButton(_ sender: Any) {
        AppDelegate
            .reachfive()
            .loginWithWebAuthn(
                email: self.emailText.text!,
                origin: AppDelegate.origin,
                scopes: scopes,
                viewController: self
            )
            .onSuccess{ authToken in self.goToProfile(authToken) }
            .onFailure { error in
                var messageAlert = ""

                switch error {
                    case .RequestError(let requestErrors):
                        messageAlert = requestErrors.errorDescription!
                    case .TechnicalError(_, let apiError):
                        messageAlert = (apiError?.errorDescription)! as String
                    default:
                        messageAlert = error.localizedDescription
                }

                let alert = UIAlertController(title: "Error", message:messageAlert, preferredStyle: UIAlertController.Style.alert)
                alert.addAction(UIAlertAction(title: "Dismiss", style: UIAlertAction.Style.default, handler: nil))

                self.present(alert, animated: true, completion: nil)
            }
    }

    func goToProfile(_ authToken: AuthToken) {
        AppDelegate.storage.save(key: AppDelegate.authKey, value: authToken)

        let storyBoard: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
        let profileController = storyBoard.instantiateViewController(
            withIdentifier: "ProfileScene"
        ) as! ProfileController

        profileController.authToken = authToken
        self.self.navigationController?.pushViewController(profileController, animated: true)
    }

}
Feedback