Setup and Configuration

Adding the Privakey CX Library to your project

The library is available on Cocoapods, so you can include it in your app the same way you include any other library. It is under the name PrivakeyCX. For instance, you can add it the following way:

  1. Edit your project's podfile
  2. Add pod 'PrivakeyCX'
  3. Run pod install from terminal

You should now be able to use the PrivakeyCX library.

Note: Sometimes XCode doesn't recognize the pods right away, and you have to build the Pods scheme before you can build your own app. If XCode cannot find the module after you perform the steps above, try following this stackoverflow post's top answer.

Library Configuration

To configure the library for your specific configuration, create the "PrivakeyConfiguration.plist" file within your app's workspace. It is automatically read when the library is instantiated.

The configurable items are:

  • PrivakeyCXURL: The URL of the Privakey CX Authorization service.
  • TelemetryOptOut: Optional. Set to true to not send telemetry events to the CX Server.
  • MaxPinAttempts: The max number of PIN attempts allowed before the device should revoke itself and clear its data in order to protect from brute force attacks against the PIN.
  • PrivakeyCXConnectTime: Sets URLSessionConfiguration.timeoutIntervalForResource within the network layer of the library. Controls how long (in seconds) to wait for an entire resource to transfer before giving up.
  • PrivakeyCXReadTimeout: Sets the URLSessionConfiguration.timeoutIntervalForRequest within the network layer of the library. Controls how long (in seconds) a task should wait for additional data to arrive before giving up.
  • PrivakeyCXJWTValidityMinutes: Controls how long (in minutes) the JSON web token that is used to authenticate network calls between the library and the Privakey CX Authorization service is valid.

Here is an example PrivakeyConfiguration.plist file.

<?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>PrivakeyCXURL</key>
    <string>https://your-cx.auth-server-domain.com:443</string>
    <key>TelemetryOptOut</key>
    <boolean>false</boolean>
    <key>MaxPinAttempts</key>
    <integer>5</integer>
    <key>PrivakeyCXConnectTime</key>
    <integer>30</integer>
    <key>PrivakeyCXReadTimeout</key>
    <integer>30</integer>
    <key>PrivakeyCXJWTValidityMinutes</key>
    <integer>30</integer>
  </dict>
</plist>

Usage

To start using the library, you must instantiate PrivakeyCX within the AppDelegate. Note the difference in the module name vs. the class name, E.G. PrivakeyCXSDK vs PrivakeyCX:

import PrivakeyCXSDK

var privakeyCX: PrivakeyCX

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
    self.privakeyCX = PrivakeyCX()
    self.privakeyCX.delegate = self
    self.privakeyCX.uiDelegate = self
}

To handle any incoming Privakey notifications, be sure to forward them to the library and don't forget to handle the event of a revocation (the device being revoked of privileges).

func application(
        _ application: UIApplication,
        didReceiveRemoteNotification userInfo: [AnyHashable : Any],
        fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) {

    self.privakeyCX.handleNotification(notificationUserInfo: userInfo) { didRevokeDevice in
        if didRevokeDevice == true {
            // the device was revoked so delete all of its data
        }
    }
        
    completionHandler(.noData)
}

Optionally, you can implement the protocol PinEntriesManagerUIDelegate for handling the UI when max pin attempts have been used and PrivakeyCXDelegate for handling many other events. Both of these are detailed on the Delegates page, but here is an example:

extension AppDelegate : PinEntriesManagerUIDelegate {
    public func pinEntry(attemptsLeft: Int) {
        DispatchQueue.main.async {
            var alert: UIAlertController?
            if attemptsLeft > 1 {
                alert = UIAlertController(title: "Invalid Pin", message: "Your Pin was entered incorrectly. You have \(attemptsLeft) tries remaining before you must rebind your device.", preferredStyle: .alert)
            }
            else if attemptsLeft == 1 {
                // prompt last attempt
                alert = UIAlertController(title: "Invalid Pin", message: "You have 1 Pin attempt remaining. If you enter your Pin improperly, your device will be disabled.", preferredStyle: .alert)
            }
            
            if let alert = alert {
                let ok = UIAlertAction(title: "Ok", style: .default, handler: nil)
                alert.addAction(ok)
                
                if let rootVC = UIApplication.shared.keyWindow?.rootViewController {
                    self.visibleViewController(rootVC: rootVC)?.present(alert, animated: true)
                }
            }
        }
    }
}

extension AppDelegate : PrivakeyCXDelegate {
    func CheckAccountStatus(didBecomeActive: Bool?, wasPinAttemptRevoked: Bool?) {
        if didRevokeDevice == true {
            // the device was revoked so delete any stored data that you may have and update the UI
        }
        else {
            // check the status of the account and device
            let pkId = <your Privakey ID>
            self.privakeyCX.getCurrentDevice(privakeyId: pkId!) { currentDevice, error in
                self.privakeyCX.getDevice(privakeyId: pkId!, deviceGuid: currentDevice!.guid!) { device, account, error in
                        
                    var vc: UIViewController?
                        
                    if account?.appUserStatusId == AccountStatus.TOKEN_SUSPENDED.getStatusId() {
                            .
                            .
                            .
                    } else if account?.appUserStatusId == AccountStatus.ADMIN_SUSPENDED.getStatusId() {
                            .
                            .
                            .
                    } else if account?.appUserStatusId == AccountStatus.REVOKED.getStatusId() {
                            .
                            .
                            .
                    } else if didBecomeActive == true {
                            .
                            .
                            .
                    }
                }
            }
        }
    }
}