Prove provides the iOS SDK in Swift. It has a download size of 2.5 MB and an install size of 1.5 MB for the minimum required components. It relies on iOS native APIs. Prove’s iOS SDK supports the earlier three major versions. Prove has seen successful transactions with iOS v11.
Prove manages a repository with the libraries to enable integration.
Execute the following to import CocoaPod from the Prove pod repository:
shell
Copy
Ask AI
# Run this command to install the cocoapods-art plugin (authored by Artifactory)gem install cocoapods-art# Run this command to add the Prove pod repositorypod repo-art add prove.jfrog.io https://prove.jfrog.io/artifactory/api/pods/libs-public-cocoapods# In your Podfile, paste in the Prove pod repository as a sourceplugin 'cocoapods-art', :sources => [ 'prove.jfrog.io']# In your Podfile, paste in the SDK podspod 'ProveAuth', '6.4.0'# Run this command to install the SDK podspod install
Unlike the Web SDK, when using the iOS SDK, use the mobile flow. Pass mobile to the Unify() function on the server. In a mobile flow, one-time password (OTP) validation is performed on the mobile phone.
In the mobile flow, once OTP validation is complete, the AuthFinishStep function executes.
The SDK requires an authToken as a parameter for the Authenticate() function. This token returns from the Unify() call of the server-side SDK. The token is session specific so it’s used for a single flow. It also expires after 15 minutes.
To start the flow, you’ll need to send a request to your back end server with the possession type, and an phone number if you are using Prove’s possession check.
Swift
Copy
Ask AI
// The below example uses native iOS URLSession, but any other// alternative networking approaches should also workfunc initialize(phoneNumber: String, possessionType: String, completion: @escaping (Result\<String, Error>) -> Void) { guard let url = URL(string: "\(backendUrl)/initialize") else { completion(.failure(URLError(.badURL))) return } var request = URLRequest(url: url) request.httpMethod = "POST" request.addValue("application/json", forHTTPHeaderField: "Accept") request.addValue("application/json", forHTTPHeaderField: "Content-Type") // Set up the request body let body: [String: Any] = [ "phoneNumber": phoneNumber, "possessionType": possessionType ] do { request.httpBody = try JSONSerialization.data(withJSONObject: body, options: \[]) } catch { completion(.failure(error)) return } // Perform the request let task = URLSession.shared.dataTask(with: request) { \_, response, error in // Handle network or connection errors if let error = error { completion(.failure(error)) return } do { if let json = try JSONSerialization.jsonObject(with: data, options: \[]) as? [String: Any], let authToken = json["authToken"] as? String { completion(.success(authToken)) } else { let parsingError = NSError(domain: "", code: 0, userInfo: [NSLocalizedDescriptionKey : "Failed to parse JSON or authToken is missing"]) completion(.failure(parsingError)) } } catch { completion(.failure(error)) } } // Start the network call task.resume()}
In the event a cellular data connection is unavailable during testing, use the Builder class. It permits simulated successful session results while connected to a Wi-Fi network. Testing using a Wi-Fi connection is useful in the Sandbox environment.
Swift
Copy
Ask AI
proveAuthSdk = ProveAuth.builder(authFinish: finishStep) .withMobileAuthTestMode() // Test mode flag .build()
The Prove Auth object is thread safe and used as a singleton. Most Prove Auth methods are blocking and therefore can’t execute in the main application thread. The application employs an executor service with a minimum of two threads to manage threads due to the SDK’s ability to process concurrent blocking requests.
Swift
Copy
Ask AI
// authToken retrieved from your server via StartAuthRequestproveAuthSdk.authenticate(authToken) { error in DispatchQueue.main.async { self.messages.finalResultMessage = "ProveAuth.authenticate returned error: \(error.localizedDescription)" print(self.messages.finalResultMessage) }}
In the AuthFinishStep, you’ll specify a function to call once the possession checks complete on the mobile phone. In the following code, you’ll notice an endpoint called /verify. This endpoint on your back end server calls the UnifyStatus() function to validate the phone number.
Swift
Copy
Ask AI
// Send a verify request.// The below example uses native iOS URLSession, but any other// alternative networking approaches should also workfunc verify(String: authId, completion: @escaping (Error?) -> Void) { guard let url = URL(string: "\(backendUrl)/verify") else { completion(URLError(.badURL)) return } // Create the request var request = URLRequest(url: url) request.httpMethod = "POST" request.addValue("application/json", forHTTPHeaderField: "Accept") request.addValue("application/json", forHTTPHeaderField: "Content-Type") // Set up the request body (empty JSON object) - authId is not needed so you can ignore. let body: [String: Any] = ["authId": authId] do { request.httpBody = try JSONSerialization.data(withJSONObject: body, options: \[]) } catch { completion(error) return } // Perform the request let task = URLSession.shared.dataTask(with: request) { \_, response, error in if let error = error { completion(error) return } catch { completion(error) } } // Start the network call task.resume()}
You can implement two functions for the OTP handling - a start and a finish step.
To set the OTP handlers, implement OtpStartStep and OtpFinishStep interfaces. The Swift snippet has an example.
Retry functionality is unavailable in OTP.
OtpStartStep example:
Swift
Copy
Ask AI
import Foundationimport ProveAuthimport SwiftUI// Implementation of OtpStartStep protocolclass MobileOtpStartStep: OtpStartStep { @ObservedObject var sheetObservable: SheetObservable var callback: OtpStartStepCallback? init(sheetObservable: SheetObservable){ self.sheetObservable = sheetObservable } // ProveAuth SDK calls this method when it is time to collect a customer's phone number for SMS OTP and/or obtain // the customer's confirmation to initiate the SMS message to the phone number provided // 'phoneNumberNeeded' argument indicates whether mobile app needs to collect the phone number func execute(phoneNumberNeeded: Bool, phoneValidationError: ProveAuthError?, callback: OtpStartStepCallback) { // here - signal to ContentView to display OtpStartView DispatchQueue.main.async { // SDK returns phoneValidationError if the phone number provided is invalid or blocked if case .phoneNumberValidationError = phoneValidationError { self.sheetObservable.isPhoneValidationError = true } else { self.sheetObservable.isPhoneValidationError = false } self.sheetObservable.isOtpStartActive = true self.sheetObservable.isPhoneNumberNeeded = phoneNumberNeeded self.callback = callback } } // Here - return collected phone number string to SDK func handlePhoneNumber(phoneNumber: String? = nil) { guard let callback = self.callback else { print("Error: OtpStartStepCallback is not set ") return } if let phoneNumber = phoneNumber { let otpStartInput = OtpStartInput(phoneNumber: phoneNumber) // This is how you pass collected phone number to SDK callback.onSuccess(input: otpStartInput) return } // If phoneNumberNeeded = false (in the OtpStartStep.execute) and phone number was already provided in the initial server-to-server call to /start endpoint // Then return nil back to SDK, Prove Auth server already got the phone number // calling onSuccess here indicates that the customer's confirmation to send SMS was obtained callback.onSuccess(input: nil) } // Here - communicate to the SDK any issues while trying to obtain the phone number. // Error should be reported if the customer explicitly cancels the SMS OTP transaction or presses the back button to exit out the SMS OTP start step screen. func handleOtpStartError() { guard let callback = self.callback else { print("Error: OtpStartStepCallback is not set ") return } callback.onError() }}
OtpFinishStep example:
Swift
Copy
Ask AI
import Foundationimport SwiftUIimport ProveAuth// Implementation of OtpFinishStep protocolclass MobileOtpFinishStep: OtpFinishStep { @ObservedObject var sheetObservable: SheetObservable var callback: OtpFinishStepCallback? init(sheetObservable: SheetObservable){ self.sheetObservable = sheetObservable } // SDK calls this method when it is time to collect OTP value delivered in the SMS message // otpError will be returned if OTP value was incorrect func execute(otpError: ProveAuthError?, callback: OtpFinishStepCallback) { self.callback = callback // here - signal to ContentView to display OtpFinishView DispatchQueue.main.async { if case .otpValidationError = otpError { print("found otpError: \(String(describing: otpError?.localizedDescription))") } self.sheetObservable.isOtpFinishActive = true } } // Here - return the OTP value to the SDK func handleOtp(_ otp: String) { guard let callback = self.callback else { print("Error: OtpFinishStepCallback is not set ") return } let otpFinishInput = OtpFinishInput(otp: otp) callback.onSuccess(input: otpFinishInput) } // Here - communicate to the SDK any issues while trying to obtain the OTP value. // Error should be reported if the customer explicitly cancels the SMS OTP transaction or presses the back button to exit out the SMS OTP finish step screen. func handleOtpFinishError() { guard let callback = self.callback else { print("Error: OtpFinishStepCallback is not set ") return } callback.onError() }}