Handling multi-factor authentication

Some institutions require multi-factor authentication (MFA) in order to complete requests, so it's a great idea to know what kind of MFA tokens you will need to handle.

πŸ“˜

Handle MFA with our Connect Widget

We strongly recommend you use our Connect Widget to handle link creation. Our widget automatically handles the entire link creation process, including all the MFA token scenarios (inputless, numeric, QR code, or text).

General flow

1918

Sample MFA flow

The general flow for MFA is:

  1. You make a POST request to the institution to retrieve some data or to create a link.
  2. Belvo sends a 428 Token Required response, detailing which MFA method is needed to complete the request.
  3. You prompt the user to input the required authentication token.
  4. You make a Complete PATCH request for the given resource with the link ID, session ID, and user-provided authentication token.
  5. Belvo sends a 201 Success message.

428 Response

Below you can see an annotated payload for a 428 Token Required response. For detailed information regarding the token_generation_data object, please see the MFA Methods section.

[
    {
        "code": "token_required", // Response code
        "message": "A MFA token is required by the institution to login", // Human-readable description of the response.
        "session": "be7a15d5f0b84d8ea60f6c12cb2a7b32", // Session ID (required in your PATCH request).
        "expiry": "720", // The duration in which the end user needs to provide a token, in seconds.
        "link": "449e388c-812b-4798-8743-7d11efb6becf", // Link ID of the end-user (required in your PATCH request).
        "token_generation_data": {
           
			// Contains details on the MFA Method required (inputless, numeric, qr, text). 
			// Please see the relevant section
			// below for detailed information.

        },
        "request_id": "b7a3a5b3a3a2b6aa28f4cc98d55cf1f1" // The ID of the request (used for debugging purposes). 
    }
]

expect_user_input

In the token_generation_data object, we include a expect_user_input parameter. When set to false, this indicates that the user just needs to, for example:

  • Scan a QR code to complete the authentication (similar to how you authenticate the Whatsapp desktop app).
  • Confirm the login on another device (similar to password-less authentication)

MFA Methods

Inputless

The Inputless MFA method requires your user to generate an authentication token using their device and provide you with the generated token. The 428 Token Required response that you receive will have inputless in the type field. In your UI, just prompt your user to add their input token.

[
    {
        "code": "token_required",
        "message": "A MFA token is required by the institution to login",
        "session": "be7a15d5f0b84d8ea60f6c12cb2a7b32",
        "expiry": "720",
        "link": "449e388c-812b-4798-8743-7d11efb6becf",
        "token_generation_data": {
            "instructions": "Use your app or device to generate a token",
            "type": "inputless", // <-- The MFA method is inputless.
            "value": null, // <-- No value is passed.
          	"expects_user_input": true // <-- Indicates that the user needs to provide you data to complete the authentication.
        },
        "request_id": "b7a3a5b3a3a2b6aa28f4cc98d55cf1f1"
    }
]

After you have received your end user's token, you make a PATCH request.

Numeric

The numeric MFA method requires that your end user inputs a code in their device in order to receive the authentication token. The code that they will need to input in their device is passed in the 428 Token Required response, where the type field will be numeric and the value field will contain the code that the user needs to input in their application. In your UI, you can display this code to your user so that they can then enter it in their application.

πŸ“˜

Numeric code expiry

The numeric code included in the 428 response is valid for up to 30 or 60 seconds (depending on the institution). If your user provides their generated code after this time, the institution returns another 428 response with a new numeric code.

[
    {
        "code": "token_required",
        "message": "A MFA token is required by the institution to login",
        "session": "731b8a5ed45245b3a2bd595382016b5e",
        "expiry": "60",
        "link": "04134743-73f9-41c3-a6dd-06cee3fab627",
        "token_generation_data": {
            "instructions": "Use this code to generate the token",
            "type": "numeric", // <-- The MFA method is numeric.
            "value": "703837", // <-- The code to display to the user.
            "expects_user_input": true // <-- Indicates that the user needs to provide you data to complete the authentication.
        },
        "request_id": "63cece2a9374b06495a16da5b2265793"
    }
]

After you have received your end user's token, you make a PATCH request.

QR code

The QR Code MFA method requires that your end user scans a QR code in order to retrieve the authentication token.

The QR code that they will need to scan with their application is passed in the 428 Token Required response, The code that they will need to input in their device is passed in the 428 Token Required response, where the type field will be qr and the value field will contain the BASE64 string representation of the QR Code. You can parse this string to generate the QR code and display it to your user in your UI.

πŸ“˜

QR code expiry

The QR code included in the 428 response is valid for up to 30 or 60 seconds (depending on the institution). If your user provides their generated code after this time, the institution returns another 428 response with a new QR code.

[
    {
        "code": "token_required",
        "message": "A MFA token is required by the institution to login",
        "session": "433142d512854cf6b10a3ccc08f3fa7d",
        "expiry": "60", 
        "link": "66a5cf30-512d-4830-b616-7dd7d6ecf09f",
        "token_generation_data": {
            "instructions": "Scan this QR code to generate the token",
            "type": "qr", // <-- The MFA method is a QR code.
            "value": "...", // <-- BASE64 string to parse and generate QR code.
          	"expects_user_input": true // <-- Indicates that the user needs to provide you data to complete the authentication
        },
        "request_id": "ce05c19b323c1caae6445aff5d4229f8"
    }
]

After you have received your end user's token, you make a PATCH request.

Text

The Text MFA method requires your user to answer a security question. The 428 Token Required response that you receive will have text in the type field. In your UI, just prompt your user to add answer their security question and use the provided string as the value of the token parameter in your PATCH request.

[
    {
        "code": "token_required",
        "message": "A MFA token is required by the institution to login",
        "session": "be7a15d5f0b84d8ea60f6c12cb2a7b32",
        "expiry": "720",
        "link": "449e388c-812b-4798-8743-7d11efb6becf",
        "token_generation_data": {
            "instructions": "Answer the question to proceed",
            "type": "text", // <-- The MFA method is an answer to a security question .
            "value": "Where were you born?", // <-- Security question user needs to answer.
          	"expects_user_input": true // <-- Indicates that the user needs to provide you data to complete the authentication
        },
        "request_id": "b7a3a5b3a3a2b6aa28f4cc98d55cf1f1"
    }
]

After you have received your end user's token, you make a PATCH request.

Send MFA token after a 428 response

When you are required to provide a token during the connection process, you will receive a 428 Token Required response and instructions on which MFA method is needed. After you have prompted the user to input their authentication token, you must send a PATCH request to the Resume endpoint of the resource you want to access.

For example:

curl -X PATCH \
  https://api.belvo.co/api/links/ \
  -H 'Content-Type: application/json' \
  -H 'Host: api.belvo.co' \
  -H 'cache-control: no-cache' \
  -d '{
    "session": "{sessionId}",
		"link": "{linkId}",
    "token": "{userToken}"
}' \
  -u [Secret Key ID]:[Secret Key PASSWORD]
client.links.resume("{sessionId}", "{userToken}", "{linkId}")
client.Links.resume(session="{sessionId}", token="{userToken}", link="{linkId}")
client.links.resume(session_id: "{sessionId}", token: "{userToken}", link: "{linkId}")

Where:

  • {sessionId} is the value in the session field you receive in the 428 Token Required response.
  • {linkId} is the value in the link field you receive in the 428 Token Required response.
  • {userToken} is the authentication token (including an answer to a security question) that your user provides.

Send MFA token with the initial request

🚧

We do not recommend that you send the MFA token with your initial request. The token may expire before it is processed by the institution, resulting in avoidable error responses. Please see Send MFA token after 428 response or use our Connect Widget.

If you know that the institution will require an MFA token as part of the request, you can pass the token as a parameter to any of our endpoints that connect to the institution:

For example:

curl -X POST \
  https://api.belvo.co/api/links/ \
  -H 'Content-Type: application/json' \
  -H 'Host: api.belvo.co' \
  -H 'cache-control: no-cache' \
  -d '{
    "institution": "{institutionName}",
		"username": "{userName}",
		"password": "{userPassword}",
		"token": "{userToken}"
}' \
  -u [Secret Key ID]:[Secret Key PASSWORD]

Where:

  • {institutionName} is the institution code your end user wants to connect to.
  • {userName} is the login username of your end user.
  • {userPassword} is the login password of your end user.
  • {userToken} is the authentication token that your end user provides.

We use the token when connecting to the institution and automatically handle the MFA process.