ForgeRock SDKs

Collect the username and password

To handle the Callback objects

  1. Implement the UI controls that collect the username and password. For each callback that is received, display a UIAlertController to collect the required information. In this case we require only the nameCallback and the passwordCallback.

    For demonstration purposes, this example uses a simple UIAlertController to collect the username and password, rather than implementing a custom UI login screen:

    else if let node = node {
        print("Node object received, handle the node")
        DispatchQueue.main.async {
            let alert = UIAlertController(title: "User Authentication", message: nil, preferredStyle: .alert)
            for callback: Callback in node.callbacks {
                if callback.type == "NameCallback", let nameCallback = callback as?
                    NameCallback {
                    alert.addTextField { (textField) in
                        textField.placeholder = nameCallback.prompt
                        textField.autocorrectionType = .no
                        textField.autocapitalizationType = .none
                    }
    
                }
                else if callback.type == "PasswordCallback",
                        let passwordCallback = callback as? PasswordCallback {
                    alert.addTextField { (textField) in
                        textField.placeholder = passwordCallback.prompt
                        textField.autocorrectionType = .no
                        textField.autocapitalizationType = .none
                    }
                }
            }
    
            let cancelAction = UIAlertAction(title: "Cancel", style: .cancel, handler: nil)
            let submitAction = UIAlertAction(title: "Next", style: .default) { (_) in
                var index = 0
                for textField in alert.textFields! {
                    let thisCallback: SingleValueCallback = node.callbacks[index] as! SingleValueCallback
                    thisCallback.setValue(textField.text)
                    index += 1
                }
                node.next { (user: FRUser?, node, error) in
                    self.handleNode(user: user, node: node, error: error)
                }
            }
    
            alert.addAction(cancelAction)
            alert.addAction(submitAction)
    
            self.present(alert, animated: true, completion: nil)
        }
    }
  2. Run the application.

  3. When you click the Login button, the UI alert displays the text fields for collecting the username and password:

    callback alerts
  4. To submit the content of the text fields to the SDK, click the Next button.

    The SDK sends the information to the server:

    • The submitAction retrieves the callback from the node to ensure that the values in the text fields can be input into the callback.

      Note that this code uses a SingleValueCallback, because both the NameCallback and the PasswordCallback inherit from the SingleValueCallback.

    • In the callback, set the value of the callback to the value of the text field.

    • Increment the value to iterate through the text fields.

    • Move to the next node, and pass the process to the handleNode() method.

    Your complete ViewController.swift should now resemble the following:

    //
    //  ViewController.swift
    //  DemoApp
    //
    
    import UIKit
    import FRAuth
    
    class ViewController: UIViewController {
    
        @IBOutlet weak var statusLabel: UILabel?
        @IBOutlet weak var loginButton: UIButton?
    
        override func viewDidLoad() {
            super.viewDidLoad()
            // Do any additional setup after loading the view.
            FRLog.setLogLevel([.error, .network])
    
            do {
                try FRAuth.start()
                print ("SDK initialized successfully")
            } catch {
                print (error)
            }
    
            updateStatus()
        }
    
        func updateStatus() {
            if let _ = FRUser.currentUser {
                statusLabel?.text = "User is authenticated"
            }
            else {
                statusLabel?.text = "User is not authenticated"
            }
        }
    
        func handleNode(user: FRUser?, node: Node?, error: Error?) {
            if let _ = user {
                print("User is authenticated")
    
                DispatchQueue.main.async {
                    self.updateStatus()
                }
            }
            else if let node = node {
                print("Node object received, handle the node")
                DispatchQueue.main.async {
                    let alert = UIAlertController(title: "User Authentication", message: nil, preferredStyle: .alert)
                    for callback: Callback in node.callbacks {
                        if callback.type == "NameCallback", let nameCallback = callback as?
                            NameCallback {
                            alert.addTextField { (textField) in
                                textField.placeholder = nameCallback.prompt
                                textField.autocorrectionType = .no
                                textField.autocapitalizationType = .none
                            }
    
                        }
                        else if callback.type == "PasswordCallback",
                                let passwordCallback = callback as? PasswordCallback {
                            alert.addTextField { (textField) in
                                textField.placeholder = passwordCallback.prompt
                                textField.autocorrectionType = .no
                                textField.autocapitalizationType = .none
                            }
                        }
                    }
    
                    let cancelAction = UIAlertAction(title: "Cancel", style: .cancel, handler: nil)
                    let submitAction = UIAlertAction(title: "Next", style: .default) { (_) in
                        var index = 0
                        for textField in alert.textFields! {
                            let thisCallback: SingleValueCallback = node.callbacks[index] as! SingleValueCallback
                            thisCallback.setValue(textField.text)
                            index += 1
                        }
                        node.next { (user: FRUser?, node, error) in
                            self.handleNode(user: user, node: node, error: error)
                        }
                    }
    
                    alert.addAction(cancelAction)
                    alert.addAction(submitAction)
    
                    self.present(alert, animated: true, completion: nil)
                }
            }
            else {
                print ("Something went wrong: \(String(describing: error))")
            }
        }
    
        @IBAction func loginButtonPressed(sender: UIButton) {
            print("Login button is pressed")
    
            FRUser.login {(user: FRUser?, node, error) in
                self.handleNode(user: user, node: node, error: error)
            }
        }
    
    }
Copyright © 2010-2023 ForgeRock, all rights reserved.