Skip to main content
Version: Next

If a customer forgets their password, they can recover their account through a three-step OTP verification process:

1. Starting the flow

Start the recovery flow by providing the customer's phone number. This sends an OTP code to the provided number and returns a flow ID for subsequent steps.

var phoneNumber : String = "+431234567"
let request = StartRecoveryRequest(phoneNumber: phoneNumber)
vipaso.user.customer.startRecoveryFlow(request: request) { result in
switch result {
case .success(let response):
print("success")
// save flow id from response.flowID for the upcoming step
case .failure(let error):
print("error: \(error.localizedDescription)")
}
}

If you debug your networking calls, you should see the following traffic:

HTTP request and response for sending the OTP code and receiving the flow identifier.

POST /identity/recovery HTTP/1.1
Content-Type: application/json
{
"identifier": "+439999999999"
}
HTTP/1.1 201 Created
Content-Type: application/json;charset=UTF-8
{
"flowId": "be204c4a-e10e-4124-9b2e-c4b81c867cce",
"expiresAt": "2024-11-27T09:05:03.517896776Z"
}

Example screenshots from our development application:

2. Verifying your phone number

In the second step, the client side sends the OTP code with the flow id and will switch flow from authentication to settings. This means that after this request the returned flow id has to be used for the upcoming calls.

let request = RecoveryOTPRequest(
code: code, // the received OTP code
flowID: flowID // the flowID from the previous step
)

vipaso.user.customer.sendRecoveryOTP(request: request) { result in
switch result {
case .success(let response):
print("success")
// save the new settingsFlowID from response.settingsFlowID for the upcoming step
// save the new sessionToken from response.sessionToken for the upcoming step
case .failure(let error):
print("error: \(error.localizedDescription)")
}
}

If you debug your networking calls, you should see the following traffic. Don't be surprised if you see a 422 error, it's used like this on purpose to get the CSRF token. Again, all the overhead is luckily hidden by the SDK APIs.

POST /a/self-service/recovery?flow=be204c4a-e10e-4124-9b2e-c4b81c867cce HTTP/1.1
Content-Type: application/json
{
"method": "code",
"code": "999999"
}
HTTP/1.1 200 OK
...
{
"id": "ABCD1234-AB12-CD34-EF56-ABCDEF123456",
"type": "api",
...
"continue_with": [
...
"action": "show_settings_ui",
"flow": {
"id": "1234ABCD-12AB-34CD-56EF-123456ABCDEF",
...
}
}
],
"transient_payload": {}
}

Example screenshots from our development application:

3. Setting the new passcode

Complete the recovery by setting a new password using the settings flow ID and session token from the previous step. The SDK does not automatically authenticate the user after password recovery, allowing you to customize the user experience (e.g., redirect to login screen).

let request = FinishRecoveryRequest(
settingsFlowID: settingsFlowID, // the settingsFlowID from the previous step (IMPORTANT: not the one from the first step)
sessionToken: sessionToken, // the sessionToken from the previous step
password: password // the new password entered by the user
)

vipaso.user.customer.finishRecoveryFlow(request: request) { result in
switch result {
case .success(let response):
print("success")
case .failure(let error):
print("error: \(error.localizedDescription)")
}
}

If you debug your networking calls, you should see the following traffic:

POST /a/self-service/settings?flow=6726b579-706a-4ebe-8742-6cd3cb73472d HTTP/1.1
Content-Type: application/json
{
"csrf_token": "80PqKCzku/7g46kof5REfxeC8PdWuYwZfOxY8xESZXg=",
"method": "password",
"password": "111111"
}
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
{
...
}

Example screenshots from our development application: