Installation
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. The iOS SDK supports the earlier three major versions. Prove has seen successful transactions with iOS v11.Xcode RequirementTo integrate with our iOS SDKs, Apps must be built with Xcode 16.0 or later.
- CocoaPods
- Swift Package Manager
Execute the following to import CocoaPod from the Prove pod repository:
shell
Report incorrect code
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 repository
pod 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 source
plugin 'cocoapods-art', :sources => [
'prove.jfrog.io'
]
# In your Podfile, paste in the SDK pods
pod 'ProveAuth', '6.6.0'
# Run this command to install the SDK pods
pod install
Step 1: Connect to JFrog Registry
Set up the registry globally (required for both Xcode UI and Package.swift):Report incorrect code
Copy
Ask AI
swift package-registry set --global "https://prove.jfrog.io/artifactory/api/swift/libs-public-swift"
swift package-registry login "https://prove.jfrog.io/artifactory/api/swift/libs-public-swift"
# Press Enter when prompted for access token
Public Registry
This is a publicly accessible registry - no password or access token is needed. Simply press Enter when prompted for an access token.
Step 2: Adding Dependencies
Method 1: Using Xcode UI
- In Xcode, go to File → Add Package Dependencies
- Search for the package you want (e.g.,
swift.proveauth) - Select the version and add to your target

swift.proveauth) in Xcode - no need to enter the full registry URL to Xcode.Method 2: Using Package.swift
Add dependencies to yourPackage.swift file:Swift
Report incorrect code
Copy
Ask AI
// swift-tools-version: 5.9
import PackageDescription
let package = Package(
name: "YourApp",
platforms: [.iOS(.v12)],
dependencies: [
.package(id: "swift.proveauth", from: "6.6.0"),
],
targets: [
.target(
name: "YourApp",
dependencies: [
.product(name: "ProveAuth", package: "swift.proveauth"),
]
)
]
)
Report incorrect code
Copy
Ask AI
swift package resolve
Send the type of flow: mobile
Unlike the Web SDK, when using the iOS SDK, use the mobile flow. Passmobile to the Unify() function on the server. In a mobile flow, the mobile phone performs one-time password (OTP) validation.
In the mobile flow, once OTP validation is complete, the AuthFinishStep function executes.
Authenticate()
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.
Retrieve authToken
To start the flow, send a request to your back-end server with the possession type. Include a phone number if you are using Prove’s possession check.
Swift
Report incorrect code
Copy
Ask AI
// The below example uses native iOS URLSession, but any other
// alternative networking approaches should also work
func 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()
}
Setup authenticator
Once you have theauthToken, build the authenticator for the mobile flow.
- Prove Possession
- Customer-Supplied Possession
Swift
Report incorrect code
Copy
Ask AI
// Object implementing ProveAuthFinishStep protocols
let finishStep = FinishAuthStep()
// Objects implementing OtpStartStep/OtpFinishStep protocols
let otpStartStep = MobileOtpStartStep()
let otpFinishStep = MobileOtpFinishStep()
let proveAuthSdk: ProveAuth
proveAuthSdk = ProveAuth.builder(authFinish: finishStep)
.withOtpFallback(otpStart: otpStartStep, otpFinish: otpFinishStep)
.build()
Swift
Report incorrect code
Copy
Ask AI
// Object implementing ProveAuthFinishStep protocols
let finishStep = FinishAuthStep()
let proveAuthSdk: ProveAuth
proveAuthSdk = ProveAuth.builder(authFinish: finishStep)
.build()
Swift
Report incorrect code
Copy
Ask AI
proveAuthSdk = ProveAuth.builder(authFinish: finishStep)
.withMobileAuthTestMode() // Test mode flag
.build()
Performing the authentication
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 app thread. The app employs an executor service with a minimum of two threads to manage threads due to the ability to process concurrent blocking requests.Swift
Report incorrect code
Copy
Ask AI
// authToken retrieved from your server via StartAuthRequest
proveAuthSdk.authenticate(authToken) { error in
DispatchQueue.main.async {
self.messages.finalResultMessage = "ProveAuth.authenticate returned error: \(error.localizedDescription)"
print(self.messages.finalResultMessage)
}
}
Validate the mobile phone
In theAuthFinishStep, specify a function to call once the possession checks complete on the mobile phone. In the following code, notice an endpoint called /verify. This endpoint on your back end server calls the UnifyStatus() function to validate the phone number.
Swift
Report incorrect code
Copy
Ask AI
// Send a verify request.
// The below example uses native iOS URLSession, but any other
// alternative networking approaches should also work
func 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()
}
Configure OTP
To use the Resend/Retry/Phone Change features, you need to install the iOS SDK version 6.5.1 or later.
withOtpFallback(otpStart: otpStartStep, otpFinish: otpFinishStep), requires implementing the OtpStartStep and OtpFinishStep.
The OTP session has a two minute timeout from when it’s sent through SMS to when the customer can enter in the OTP.
- Default
- Prompt for Phone Number
- Resend
- Retry OTP
- Phone Number Change
Follow these instructions if you are implementing OTP and you are passing in the phone number on the Call the
/unify endpoint. In this case, you’ve already prompted for a phone number so you don’t need to prompt for it in the client SDK.Since you passed the phone number in the Unify() function, call callback.onSuccess(input: nil) to communicate to the SDK you have the customer’s agreement to deliver the SMS message.Swift
Report incorrect code
Copy
Ask AI
class OtpStartStepNoPrompt: OtpStartStep {
@ObservedObject var sheetObservable: SheetObservable
var callback: OtpStartStepCallback?
init(sheetObservable: SheetObservable) {
self.sheetObservable = sheetObservable
}
// Implement this method to handle phone number collection for SMS OTP,
// or to obtain user confirmation for initiating an SMS message.
func execute(
phoneNumberNeeded: Bool, phoneValidationError: ProveAuthError?, callback: OtpStartStepCallback
) {
self.callback = callback
// Since no phone number is needed, don't prompt the user.
callback.onSuccess(input: nil)
}
}
callback.onError() method to communicate to the SDK any issues while trying to obtain the phone number or the OTP. Report an error if the customer cancels the SMS transaction or presses the back button to leave the screen.Swift
Report incorrect code
Copy
Ask AI
class OtpFinishStepNoPrompt: OtpFinishStep {
@ObservedObject var sheetObservable: SheetObservable
var callback: OtpFinishStepCallback?
init(sheetObservable: SheetObservable) {
self.sheetObservable = sheetObservable
}
// Implement this method to collect the OTP value delivered via SMS.
func execute(otpError: ProveAuthError?, callback: OtpFinishStepCallback) {
self.callback = callback
// Handle the OTP validation error if present.
// Signal to UI components to display OtpFinishView
DispatchQueue.main.async {
if case .otpValidationError = otpError {
print("found otpError: \(String(describing: otpError?.localizedDescription))")
// Signal to your UI components that the last provided OTP is invalid
self.sheetObservable.isOtpValidationError = true
} else {
self.sheetObservable.isOtpValidationError = false
}
self.sheetObservable.isOtpFinishActive = true
}
}
// Provide the collected OTP value to the SDK for validation.
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)
}
// Notify the SDK of any issues encountered while obtaining the OTP value or if the user cancels the OTP flow.
func handleOtpFinishError() {
guard let callback = self.callback else {
print("Error: OtpFinishStepCallback is not set ")
return
}
callback.onError()
}
}
Follow these instructions if implementing MobileAuth in the US and collecting the phone number only if MobileAuth fails. This will implement OTP without allowing for SMS resends and phone number changes. If you do want those capabilities, please reference the subsequent tabs (Resend, Retry OTP, and Phone Number Change).In the start step, call the The finish step is implemented the same as the previous tab:
International MobileAuth requires phone number input, whereas US MobileAuth allows silent authentication without phone number input.
callback.onSuccess(input: otpStartInput) method to return the collected phone number to the SDK.Swift
Report incorrect code
Copy
Ask AI
import Foundation
import ProveAuth
import SwiftUI
class OtpStartStepWithPrompt: OtpStartStep {
@ObservedObject var sheetObservable: SheetObservable
var callback: OtpStartStepCallback?
init(sheetObservable: SheetObservable) {
self.sheetObservable = sheetObservable
}
func execute(
phoneNumberNeeded: Bool, phoneValidationError: ProveAuthError?, callback: OtpStartStepCallback
) {
self.callback = callback
if !phoneNumberNeeded {
// If no phone number is needed, then don't prompt the user.
callback.onSuccess(input: nil)
} else {
DispatchQueue.main.async {
// If a phone number validation error is detected, ensure it is handled to provide feedback to the user.
if case .phoneNumberValidationError = phoneValidationError {
print(
"found phoneValidationError: \(String(describing: phoneValidationError?.localizedDescription))"
)
// Update UI components to display OtpStartView with the phone number validation error.
self.sheetObservable.isPhoneValidationError = true
} else {
self.sheetObservable.isPhoneValidationError = false
}
// Update UI components to display OtpStartView if a phone number is needed.
self.sheetObservable.isOtpStartActive = true
}
}
}
// Return collected phone number to the SDK
func handlePhoneNumber(phoneNumber: String) {
guard let callback = self.callback else {
print("Error: OtpStartStepCallback is not set ")
return
}
let otpStartInput = OtpStartInput(phoneNumber: phoneNumber)
// This is how you pass collected phone number to SDK
callback.onSuccess(input: otpStartInput)
}
// Communicate any issues encountered while trying to obtain the phone number to the SDK.
// 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()
}
}
Swift
Report incorrect code
Copy
Ask AI
class OtpFinishStepNoPrompt: OtpFinishStep {
@ObservedObject var sheetObservable: SheetObservable
var callback: OtpFinishStepCallback?
init(sheetObservable: SheetObservable) {
self.sheetObservable = sheetObservable
}
// Implement this method to collect the OTP value delivered via SMS.
func execute(otpError: ProveAuthError?, callback: OtpFinishStepCallback) {
self.callback = callback
// Handle the OTP validation error if present.
// Signal to UI components to display OtpFinishView
DispatchQueue.main.async {
if case .otpValidationError = otpError {
print("found otpError: \(String(describing: otpError?.localizedDescription))")
// Signal to your UI components that the last provided OTP is invalid
self.sheetObservable.isOtpValidationError = true
} else {
self.sheetObservable.isOtpValidationError = false
}
self.sheetObservable.isOtpFinishActive = true
}
}
// Provide the collected OTP value to the SDK for validation.
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)
}
// Notify the SDK of any issues encountered while obtaining the OTP value or if the user cancels the OTP flow.
func handleOtpFinishError() {
guard let callback = self.callback else {
print("Error: OtpFinishStepCallback is not set ")
return
}
callback.onError()
}
}
Follow these instructions to allow the customer to request a new OTP via SMS using the same phone number. There is a max of three send attempts including the initial message.The start step is implemented the same as the previous tab:You can then send a new OTP SMS to the same phone number by implementing the finish step like this:
Swift
Report incorrect code
Copy
Ask AI
import Foundation
import ProveAuth
import SwiftUI
class OtpStartStepWithPrompt: OtpStartStep {
@ObservedObject var sheetObservable: SheetObservable
var callback: OtpStartStepCallback?
init(sheetObservable: SheetObservable) {
self.sheetObservable = sheetObservable
}
func execute(
phoneNumberNeeded: Bool, phoneValidationError: ProveAuthError?, callback: OtpStartStepCallback
) {
self.callback = callback
if !phoneNumberNeeded {
// If no phone number is needed, then don't prompt the user.
callback.onSuccess(input: nil)
} else {
DispatchQueue.main.async {
// If a phone number validation error is detected, ensure it is handled to provide feedback to the user.
if case .phoneNumberValidationError = phoneValidationError {
print(
"found phoneValidationError: \(String(describing: phoneValidationError?.localizedDescription))"
)
// Update UI components to display OtpStartView with the phone number validation error.
self.sheetObservable.isPhoneValidationError = true
} else {
self.sheetObservable.isPhoneValidationError = false
}
// Update UI components to display OtpStartView if a phone number is needed.
self.sheetObservable.isOtpStartActive = true
}
}
}
// Return collected phone number to the SDK
func handlePhoneNumber(phoneNumber: String) {
guard let callback = self.callback else {
print("Error: OtpStartStepCallback is not set ")
return
}
let otpStartInput = OtpStartInput(phoneNumber: phoneNumber)
// This is how you pass collected phone number to SDK
callback.onSuccess(input: otpStartInput)
}
// Communicate any issues encountered while trying to obtain the phone number to the SDK.
// 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()
}
}
Swift
Report incorrect code
Copy
Ask AI
class OtpFinishStepMultipleResend: OtpFinishStep {
@ObservedObject var sheetObservable: SheetObservable
var callback: OtpFinishStepCallback?
init(sheetObservable: SheetObservable) {
self.sheetObservable = sheetObservable
}
// Implement this method to collect the OTP value delivered in the SMS message.
func execute(otpError: ProveAuthError?, callback: OtpFinishStepCallback) {
self.callback = callback
// Handle the OTP validation error if present.
// Update your UI to display the OtpFinishView
DispatchQueue.main.async {
if case .otpValidationError = otpError {
print("found otpError: \(String(describing: otpError?.localizedDescription))")
// Update your UI to indicate that the provided OTP is invalid
self.sheetObservable.isOtpValidationError = true
} else {
self.sheetObservable.isOtpValidationError = false
}
self.sheetObservable.isOtpFinishActive = true
}
}
// 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)
}
// Communicate to the SDK any issues when host app trys to obtain the OTP value
// or when users cancel the OTP flow
func handleOtpFinishError() {
guard let callback = self.callback else {
print("Error: OtpFinishStepCallback is not set ")
return
}
callback.onError()
}
// Call this method to request a new OTP code for the same mobile number.
func sendNewOtp() {
guard let callback = self.callback else {
print("Error: OtpFinishStepCallback is not set ")
return
}
callback.onOtpResend()
}
}
Follow these instructions to allow the customer to re-enter the OTP PIN if they type it wrong. There is a max of 3 attempts. To implement this functionality, you also need to pass in The finish step is implemented the same as either of the the previous tabs - no client side code changes necessary. If the OTP is invalid, the finish step will be called again to prompt the user for a new input. Once the max attempts is reached, the
allowOTPRetry=true to the /unify endpoint.The start step is implemented the same as either of the the previous tabs - no client side code changes necessary:Swift
Report incorrect code
Copy
Ask AI
import Foundation
import ProveAuth
import SwiftUI
class OtpStartStepWithPrompt: OtpStartStep {
@ObservedObject var sheetObservable: SheetObservable
var callback: OtpStartStepCallback?
init(sheetObservable: SheetObservable) {
self.sheetObservable = sheetObservable
}
func execute(
phoneNumberNeeded: Bool, phoneValidationError: ProveAuthError?, callback: OtpStartStepCallback
) {
self.callback = callback
if !phoneNumberNeeded {
// If no phone number is needed, then don't prompt the user.
callback.onSuccess(input: nil)
} else {
DispatchQueue.main.async {
// If a phone number validation error is detected, ensure it is handled to provide feedback to the user.
if case .phoneNumberValidationError = phoneValidationError {
print(
"found phoneValidationError: \(String(describing: phoneValidationError?.localizedDescription))"
)
// Update UI components to display OtpStartView with the phone number validation error.
self.sheetObservable.isPhoneValidationError = true
} else {
self.sheetObservable.isPhoneValidationError = false
}
// Update UI components to display OtpStartView if a phone number is needed.
self.sheetObservable.isOtpStartActive = true
}
}
}
// Return collected phone number to the SDK
func handlePhoneNumber(phoneNumber: String) {
guard let callback = self.callback else {
print("Error: OtpStartStepCallback is not set ")
return
}
let otpStartInput = OtpStartInput(phoneNumber: phoneNumber)
// This is how you pass collected phone number to SDK
callback.onSuccess(input: otpStartInput)
}
// Communicate any issues encountered while trying to obtain the phone number to the SDK.
// 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()
}
}
AuthFinish function will be called.Swift
Report incorrect code
Copy
Ask AI
class OtpFinishStepNoPrompt: OtpFinishStep {
@ObservedObject var sheetObservable: SheetObservable
var callback: OtpFinishStepCallback?
init(sheetObservable: SheetObservable) {
self.sheetObservable = sheetObservable
}
// Implement this method to collect the OTP value delivered via SMS.
func execute(otpError: ProveAuthError?, callback: OtpFinishStepCallback) {
self.callback = callback
// Handle the OTP validation error if present.
// Signal to UI components to display OtpFinishView
DispatchQueue.main.async {
if case .otpValidationError = otpError {
print("found otpError: \(String(describing: otpError?.localizedDescription))")
// Signal to your UI components that the last provided OTP is invalid
self.sheetObservable.isOtpValidationError = true
} else {
self.sheetObservable.isOtpValidationError = false
}
self.sheetObservable.isOtpFinishActive = true
}
}
// Provide the collected OTP value to the SDK for validation.
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)
}
// Notify the SDK of any issues encountered while obtaining the OTP value or if the user cancels the OTP flow.
func handleOtpFinishError() {
guard let callback = self.callback else {
print("Error: OtpFinishStepCallback is not set ")
return
}
callback.onError()
}
}
Follow these instructions to allow the customer to re-enter their phone number. There is a max of three entries/send attempts.The start step is implemented the same as the previous tab:You can prompt for a new phone number by implementing the finish step like this:
Manual Request RequiredTo enable phone number change capabilities on your credentials, contact your Prove representative.
Swift
Report incorrect code
Copy
Ask AI
import Foundation
import ProveAuth
import SwiftUI
class OtpStartStepWithPrompt: OtpStartStep {
@ObservedObject var sheetObservable: SheetObservable
var callback: OtpStartStepCallback?
init(sheetObservable: SheetObservable) {
self.sheetObservable = sheetObservable
}
func execute(
phoneNumberNeeded: Bool, phoneValidationError: ProveAuthError?, callback: OtpStartStepCallback
) {
self.callback = callback
if !phoneNumberNeeded {
// If no phone number is needed, then don't prompt the user.
callback.onSuccess(input: nil)
} else {
DispatchQueue.main.async {
// If a phone number validation error is detected, ensure it is handled to provide feedback to the user.
if case .phoneNumberValidationError = phoneValidationError {
print(
"found phoneValidationError: \(String(describing: phoneValidationError?.localizedDescription))"
)
// Update UI components to display OtpStartView with the phone number validation error.
self.sheetObservable.isPhoneValidationError = true
} else {
self.sheetObservable.isPhoneValidationError = false
}
// Update UI components to display OtpStartView if a phone number is needed.
self.sheetObservable.isOtpStartActive = true
}
}
}
// Return collected phone number to the SDK
func handlePhoneNumber(phoneNumber: String) {
guard let callback = self.callback else {
print("Error: OtpStartStepCallback is not set ")
return
}
let otpStartInput = OtpStartInput(phoneNumber: phoneNumber)
// This is how you pass collected phone number to SDK
callback.onSuccess(input: otpStartInput)
}
// Communicate any issues encountered while trying to obtain the phone number to the SDK.
// 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()
}
}
Swift
Report incorrect code
Copy
Ask AI
class OtpFinishStepWithPhoneChange: OtpFinishStep {
@ObservedObject var sheetObservable: SheetObservable
var callback: OtpFinishStepCallback?
init(sheetObservable: SheetObservable) {
self.sheetObservable = sheetObservable
}
// Implement this method to collect the OTP value delivered via SMS.
func execute(otpError: ProveAuthError?, callback: OtpFinishStepCallback) {
self.callback = callback
// Handle the OTP validation error if present.
// Update your UI to display the OTP finish view.
DispatchQueue.main.async {
if case .otpValidationError = otpError {
print("found otpError: \(String(describing: otpError?.localizedDescription))")
// Update your UI to indicate that the provided OTP is invalid.
self.sheetObservable.isOtpValidationError = true
} else {
self.sheetObservable.isOtpValidationError = false
}
self.sheetObservable.isOtpFinishActive = true
}
}
// Return the collected 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)
}
// When callback.onMobileNumberChange() is evoked, OtpStartStep will be re-initiated
// so that end-users can enter a different phone number via OtpStartStep.
func handleMobileNumberChange() {
guard let callback = self.callback else {
print("Error: OtpFinishStepCallback is not set")
return
}
callback.onMobileNumberChange()
}
}

