Managed Auth - Recovering Account

In case you forgot the passcode of your Pay user, you can use the SDK to recover your account. The recovery process involves three main steps: starting the recovery flow, verifying your phone number with an OTP code, and finally setting a new password.

Overview

  1. Starting the Recovery Flow
  2. Verifying Your Phone Number
  3. Setting the New Passcode

1. Starting the Recovery Flow

It's a simple call to start the flow in the background. The backend receives the phone number it should send the OTP verification to and will reply with the flow identifier you will need to use in follow-up calls.

// Create a recovery request with the user's phone number
val request = StartRecoveryRequest(phoneNumber = "+431234567")

// Start the recovery flow
try {
    val recoveryResponse = vipasoPay.user.startRecoveryFlow(request)
    // Success: you need to save flowId for the upcoming step
    val flowId = recoveryResponse.flowId
} catch (e: Throwable) {
    // Error: handle any server or network errors
    Log.e("Recovery", "Error starting recovery flow: ${e.message}")
}

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.

// Create a recovery OTP verification request with the received code and flow ID
val request = RecoveryOTPRequest(
    code = "123456", // the received OTP code
    flowId = flowId // the flowID from the previous step
)

// Send the OTP verification
try {
    val otpResponse = vipasoPay.user.sendRecoveryOTP(request)
    // Success: save the new settingsFlowId and sessionToken for the upcoming step
    val settingsFlowId = otpResponse.settingsFlowId
    val sessionToken = otpResponse.sessionToken
} catch (e: Throwable) {
    // Error: handle any server or network errors
    Log.e("Recovery", "Error verifying OTP: ${e.message}")
}

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

The last step is to update your passcode. You will need to send the received session token and the new passcode to the received settings flow id. It's important to note that the SDK does not automatically authenticate you again. This is to let you implement your user experience the way you prefer. Once you get a success response, you can navigate your users to the login screen for example.

// Create a request to finish the recovery flow with the new password
val request = FinishRecoveryRequest(
    settingsFlowId = settingsFlowId, // from previous step
    sessionToken = sessionToken, // from previous step
    password = "new_secure_password" // the new password entered by the user
)

// Complete the recovery flow
try {
    val finishResponse = vipasoPay.user.finishRecoveryFlow(request)
    // Success: recovery process completed successfully
    // You can now navigate to the login screen
} catch (e: Throwable) {
    // Error: handle any server or network errors
    Log.e("Recovery", "Error setting new password: ${e.message}")
}

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: