Silent Authentication Synchronous Implementation

Introduction

This guide explains how to implement Silent Authentication using the synchronous approach, where your backend waits for a direct response after redirecting the user.

Note: if using a Synchronous implementation, switching on Verify capabilities on the application dashboard is optional, as this only switches the ability to receive status webhooks (that are not required for a Synchronous implementation).

The following diagram shows the necessary steps to implement the synchronous version of Silent Authentication:

Request Verification Code

To start the silent authentication process, make a request to /verify endpoint. In the following example, the workflow specifies that Verify will first attempt to use Silent Authentication. If for any reason the request fails, it will then fallback to SMS, followed by a voice call OTP.

Note: if using multiple channels, silent authentication must be the first channel in the workflow.

To run the example, replace the following variables in the sample code with your own values:

Variable Description
JWT Authenticates the API request using JWT.
VERIFY_BRAND_NAME The name of your company or service, shown to the user in the verification message.
VONAGE_APPLICATION_PRIVATE_KEY_PATH Private key of your application.
VONAGE_APPLICATION_ID Application ID of your application.
VERIFY_NUMBER The phone number to send the OTP to, in E.164 format (e.g., +44111223344).

Write the code

Add the following to request.sh:

curl -X POST "https://api.nexmo.com/v2/verify" \
  -H "Authorization: Bearer $JWT"\
  -H 'Content-Type: application/json' \
  -d $'{
	 "brand": "'$VERIFY_BRAND_NAME'",
   "workflow": [
      {
         "channel": "silent_auth",
         "to": "'$VERIFY_NUMBER'"
      },
      {
         "channel": "sms",
         "to": "'$VERIFY_NUMBER'"
      },
      {
         "channel": "voice",
         "to": "'$VERIFY_NUMBER'"
      }
   ]
}'

View full source

Run your code

Save this file to your machine and run it:

sh request.sh

Prerequisites

npm install @vonage/server-sdk @vonage/verify2

Create a file named send-request-with-fallback.js and add the following code:

const { Vonage } = require('@vonage/server-sdk');
const { Channels, SilentAuthChannel } = require('@vonage/verify2');

const vonage = new Vonage({
  applicationId: VONAGE_APPLICATION_ID,
  privateKey: VONAGE_APPLICATION_PRIVATE_KEY_PATH,
});

View full source

Write the code

Add the following to send-request-with-fallback.js:

vonage.verify2.newRequest({
  brand: VERIFY_BRAND_NAME,
  workflow: [
    {
      channel: SilentAuthChannel.SILENT_AUTH,
      to: VERIFY_NUMBER,
    },
    {
      channel: Channels.SMS,
      to: VERIFY_NUMBER,
    },
    {
      channel: Channels.VOICE,
      to: VERIFY_NUMBER,
    },
  ],
})
  .then(({requestId}) => console.log(requestId))
  .catch((err) => console.error(err));

View full source

Run your code

Save this file to your machine and run it:

node send-request-with-fallback.js

Prerequisites

Add the following to build.gradle:

implementation 'com.vonage:server-sdk-kotlin:2.1.1'

Create a file named SendVerificationRequestWithFallback and add the following code to the main method:

val client = Vonage {
    applicationId(VONAGE_APPLICATION_ID)
    privateKeyPath(VONAGE_PRIVATE_KEY_PATH)
}

View full source

Write the code

Add the following to the main method of the SendVerificationRequestWithFallback file:

val response = client.verify.sendVerification(VERIFY_BRAND_NAME) {
    silentAuth(VERIFY_NUMBER)
    sms(VERIFY_NUMBER)
    voice(VERIFY_NUMBER)
}

View full source

Run your code

We can use the application plugin for Gradle to simplify the running of our application. Update your build.gradle with the following:

apply plugin: 'application'
mainClassName = project.hasProperty('main') ? project.getProperty('main') : ''

Run the following gradle command to execute your application, replacing com.vonage.quickstart.kt.verify with the package containing SendVerificationRequestWithFallback:

gradle run -Pmain=com.vonage.quickstart.kt.verify.SendVerificationRequestWithFallback

Prerequisites

Add the following to build.gradle:

implementation 'com.vonage:server-sdk:9.3.1'

Create a file named SendRequestWithFallback and add the following code to the main method:

VonageClient client = VonageClient.builder()
		.applicationId(VONAGE_APPLICATION_ID)
		.privateKeyPath(VONAGE_PRIVATE_KEY_PATH)
		.build();

View full source

Write the code

Add the following to the main method of the SendRequestWithFallback file:

VerificationResponse response = client.getVerify2Client().sendVerification(
		VerificationRequest.builder()
			.addWorkflow(new SilentAuthWorkflow(VERIFY_NUMBER))
			.addWorkflow(new SmsWorkflow(VERIFY_NUMBER))
			.addWorkflow(new VoiceWorkflow(VERIFY_NUMBER))
			.brand(VERIFY_BRAND_NAME).build()
);

View full source

Run your code

We can use the application plugin for Gradle to simplify the running of our application. Update your build.gradle with the following:

apply plugin: 'application'
mainClassName = project.hasProperty('main') ? project.getProperty('main') : ''

Run the following gradle command to execute your application, replacing com.vonage.quickstart.verify2 with the package containing SendRequestWithFallback:

gradle run -Pmain=com.vonage.quickstart.verify2.SendRequestWithFallback

Prerequisites

Install-Package Vonage

Create a file named StartVerificationRequestWithFallback.cs and add the following code:

using Vonage;
using Vonage.Request;
using Vonage.VerifyV2.StartVerification;
using Vonage.VerifyV2.StartVerification.Sms;
using Vonage.VerifyV2.StartVerification.Voice;
using Vonage.VerifyV2.StartVerification.SilentAuth;

View full source

Add the following to StartVerificationRequestWithFallback.cs:

var credentials = Credentials.FromAppIdAndPrivateKeyPath(VONAGE_APPLICATION_ID, VONAGE_APPLICATION_PRIVATE_KEY_PATH);
var client = new VonageClient(credentials);

View full source

Write the code

Add the following to StartVerificationRequestWithFallback.cs:

var request = StartVerificationRequest.Build()
    .WithBrand(BRAND_NAME)
    .WithWorkflow(SilentAuthWorkflow.Parse(TO_NUMBER))
    .WithFallbackWorkflow(SmsWorkflow.Parse(TO_NUMBER))
    .WithFallbackWorkflow(VoiceWorkflow.Parse(TO_NUMBER))
    .Create();
var response = await client.VerifyV2Client.StartVerificationAsync(request);

View full source

Prerequisites

composer require vonage/client

Create a file named request.php and add the following code:

$client = new Vonage\Client(
    new Vonage\Client\Credentials\Keypair(VONAGE_APPLICATION_PRIVATE_KEY_PATH, VONAGE_APPLICATION_ID),
);

View full source

Write the code

Add the following to request.php:

$newRequest = new \Vonage\Verify2\Request\SilentAuthRequest(VERIFY_NUMBER, VERIFY_BRAND_NAME);
$smsWorkflow = new \Vonage\Verify2\VerifyObjects\VerificationWorkflow(\Vonage\Verify2\VerifyObjects\VerificationWorkflow::WORKFLOW_SMS, VERIFY_NUMBER);
$newRequest->addWorkflow($smsWorkflow);
$voiceWorkflow = new \Vonage\Verify2\VerifyObjects\VerificationWorkflow(\Vonage\Verify2\VerifyObjects\VerificationWorkflow::WORKFLOW_VOICE, VERIFY_NUMBER);
$newRequest->addWorkflow($voiceWorkflow);

$client->verify2()->startVerification($newRequest);

View full source

Run your code

Save this file to your machine and run it:

php request.php

Prerequisites

pip install vonage python-dotenv

Write the code

Add the following to send-request-with-fallback.py:

from vonage import Auth, Vonage
from vonage_verify import (SmsChannel, VoiceChannel, SilentAuthChannel,
                           StartVerificationResponse, VerifyRequest)

client = Vonage(
    Auth(
        application_id=VONAGE_APPLICATION_ID,
        private_key=VONAGE_PRIVATE_KEY,
    )
)

verify_request = VerifyRequest(
    brand=VERIFY_BRAND_NAME,
    workflow=[
        SilentAuthChannel(to=VERIFY_NUMBER),
        SmsChannel(to=VERIFY_NUMBER),
        VoiceChannel(to=VERIFY_NUMBER),
    ],
)

response: StartVerificationResponse = client.verify.start_verification(verify_request)
pprint(response)

View full source

Run your code

Save this file to your machine and run it:

python verify/send-request-with-fallback.py

Prerequisites

gem install vonage

Create a file named request.rb and add the following code:

client = Vonage::Client.new(
  application_id: VONAGE_APPLICATION_ID,
  private_key: VONAGE_PRIVATE_KEY
)

View full source

Write the code

Add the following to request.rb:

client.verify2.start_verification(
  brand: VERIFY_BRAND_NAME,
  workflow: [
    {
      channel: 'silent_auth',
      to: VERIFY_NUMBER
    },
    {
      channel: 'sms',
      to: VERIFY_NUMBER
    },
    {
      channel: 'voice',
      to: VERIFY_NUMBER
    }
  ]
)

View full source

Run your code

Save this file to your machine and run it:

ruby request.rb

If the request is successful and the number is supported, you will receive a 200 Ok response containing a request_id and a check_url in the body:

{
  "request_id": "c11236f4-00bf-4b89-84ba-88b25df97315",
  "check_url": "https://api.nexmo.com/v2/verify/31eaf23d-b2db-4c42-9d1d-e847e75ab330/silent-auth/redirect"
}

Until the request expires or is cancelled, check_url can be used to perform a Silent Authentication check. Upon receiving this response, you need to make a GET request to the check_url from the mobile device you are trying to authenticate.

Important: The check_url request must be executed over a mobile data connection (not Wi-Fi). The recommended way to ensure this is to use the Vonage Client SDK (iOS or Android), which automatically routes the request through the device’s cellular network. See the Bypass Wi-Fi for Silent Authentication guide for more details.

Once you've made the GET request, you'll receive a number of HTTP 302 redirects depending on the territory and carrier the target device is using:

HTTP/1.1 302 Found
Location: https://eu.api.silentauth.com/phone_check/v0.2/checks/31eaf23d-b2db-4c42-9d1d-e847e75ab330/redirect

Following the redirects will result in either a HTTP 200 or HTTP 409 response depending on whether the request is valid. If there is a problem with the network, you'll see a response like this:

HTTP/1.1 409 CONFLICT
Content-Type: application/json

{
  "title": "Network error",
  "detail": "The Silent Auth request could not be completed due to formatting or the carrier is not supported."
}

A full list of potential error codes can be found in the API Specification.

If the request is valid, you will receive an HTTP 200 response containing your request_id and a code:

{
  "request_id": "c11236f4-00bf-4b89-84ba-88b25df97315",
  "code": "si9sfG"
}

Note: To ensure a secure authentication check and mitigate against a potential man in the middle attack, store the original request_id and compare it with the request_id returned in the response. If the IDs don't match, the silent authentication check should be aborted. See our sample application for an example implementation of how to mitigate against the attack.

Check the Supplied Verification Code

Once the end-user receives the code, you must send a POST request to the /v2/verify/{request_id} endpoint, replacing {request_id} with the ID you received in the previous call.

To run the example, replace the following variables in the sample code with your own values:

Variable Description
JWT Authenticates the API request using JWT.
VERIFY_REQUEST_ID The request_id received in the previous step.
VONAGE_APPLICATION_PRIVATE_KEY_PATH Private key of your application.
VONAGE_APPLICATION_ID Application ID of your application.
VERIFY_CODE The verification code received by the end-user

Write the code

Add the following to check-verification-code.sh:

curl -X POST "https://api.nexmo.com/v2/verify/$VERIFY_REQUEST_ID" \
  -H "Authorization: Bearer $JWT"\
  -H 'Content-Type: application/json' \
  -d $'{
    "code": "'$VERIFY_CODE'"
  }'

View full source

Run your code

Save this file to your machine and run it:

sh check-verification-code.sh

Prerequisites

npm install @vonage/server-sdk

Create a file named check-verification-code.js and add the following code:

const { Vonage } = require('@vonage/server-sdk');

const vonage = new Vonage ({
  applicationId: VONAGE_APPLICATION_ID,
  privateKey: VONAGE_APPLICATION_PRIVATE_KEY_PATH,
});

View full source

Write the code

Add the following to check-verification-code.js:

vonage.verify2.checkCode(VERIFY_REQUEST_ID, VERIFY_CODE)
  .then((status) => console.log(`The status is ${status}`),
  )
  .catch((err) => console.error(err));

View full source

Run your code

Save this file to your machine and run it:

node check-verification-code.js

Prerequisites

Add the following to build.gradle:

implementation 'com.vonage:server-sdk-kotlin:2.1.1'

Create a file named CheckVerificationCode and add the following code to the main method:

val client = Vonage {
    applicationId(VONAGE_APPLICATION_ID)
    privateKeyPath(VONAGE_PRIVATE_KEY_PATH)
}

View full source

Write the code

Add the following to the main method of the CheckVerificationCode file:

if (client.verify.request(VERIFY_REQUEST_ID).isValidVerificationCode(VERIFY_CODE)) {
    println("Code matches.")
}

View full source

Run your code

We can use the application plugin for Gradle to simplify the running of our application. Update your build.gradle with the following:

apply plugin: 'application'
mainClassName = project.hasProperty('main') ? project.getProperty('main') : ''

Run the following gradle command to execute your application, replacing com.vonage.quickstart.kt.verify with the package containing CheckVerificationCode:

gradle run -Pmain=com.vonage.quickstart.kt.verify.CheckVerificationCode

Prerequisites

Add the following to build.gradle:

implementation 'com.vonage:server-sdk:9.3.1'

Create a file named CheckVerificationCode and add the following code to the main method:

VonageClient client = VonageClient.builder()
		.applicationId(VONAGE_APPLICATION_ID)
		.privateKeyPath(VONAGE_PRIVATE_KEY_PATH)
		.build();

View full source

Write the code

Add the following to the main method of the CheckVerificationCode file:

try {
	client.getVerify2Client().checkVerificationCode(VERIFY_REQUEST_UUID, VERIFY_CODE);
	System.out.println("SUCCESS - code matches!");
}
catch (VerifyResponseException ex) {
	switch (ex.getStatusCode()) {
		case 400: // Code does not match
		case 404: // Already verified or not found
		case 409: // Workflow does not support code
		case 410: // Incorrect code provided too many times
		case 429: // Rate limit exceeded
		default:  // Unknown or internal server error (500)
			ex.printStackTrace();
	}
}

View full source

Run your code

We can use the application plugin for Gradle to simplify the running of our application. Update your build.gradle with the following:

apply plugin: 'application'
mainClassName = project.hasProperty('main') ? project.getProperty('main') : ''

Run the following gradle command to execute your application, replacing com.vonage.quickstart.verify2 with the package containing CheckVerificationCode:

gradle run -Pmain=com.vonage.quickstart.verify2.CheckVerificationCode

Prerequisites

Install-Package Vonage

Create a file named VerifyCodeRequest.cs and add the following code:

using Vonage;
using Vonage.Request;

View full source

Add the following to VerifyCodeRequest.cs:

var credentials = Credentials.FromAppIdAndPrivateKeyPath(VONAGE_APPLICATION_ID, VONAGE_APPLICATION_PRIVATE_KEY_PATH);
var client = new VonageClient(credentials);

View full source

Write the code

Add the following to VerifyCodeRequest.cs:

var request = Vonage.VerifyV2.VerifyCode.VerifyCodeRequest.Build()
    .WithRequestId(REQUEST_ID)
    .WithCode(CODE)
    .Create();
var response = await client.VerifyV2Client.VerifyCodeAsync(request);

View full source

Prerequisites

composer require vonage/client

Create a file named send_code.php and add the following code:

$client = new Vonage\Client(
    new Vonage\Client\Credentials\Keypair(VONAGE_APPLICATION_PRIVATE_KEY_PATH, VONAGE_APPLICATION_ID),
);

View full source

Write the code

Add the following to send_code.php:

try {
    $client->verify2()->check(REQUEST_ID, CODE);
} catch (\Exception $e) {
    var_dump($e->getMessage());
}

View full source

Run your code

Save this file to your machine and run it:

php send_code.php

Prerequisites

pip install vonage python-dotenv

Write the code

Add the following to check-verification-code.py:

from vonage import Auth, Vonage
from vonage_verify import CheckCodeResponse

client = Vonage(
    Auth(
        application_id=VONAGE_APPLICATION_ID,
        private_key=VONAGE_PRIVATE_KEY,
    )
)

response: CheckCodeResponse = client.verify.check_code(
    request_id=VERIFY_REQUEST_ID, code=VERIFY_CODE
)
print(response)

View full source

Run your code

Save this file to your machine and run it:

python verify/check-verification-code.py

Prerequisites

gem install vonage

Create a file named check.rb and add the following code:

client = Vonage::Client.new(
  application_id: VONAGE_APPLICATION_ID,
  private_key: VONAGE_PRIVATE_KEY
)

View full source

Write the code

Add the following to check.rb:

client.verify2.check_code(
  request_id: VERIFY_REQUEST_ID,
  code: VERIFY_CODE
)

View full source

Run your code

Save this file to your machine and run it:

ruby check.rb

Note: a code for a silent authentication workflow can only be checked once.

If the code is valid, you will receive a final response with the status completed:

{
   "request_id": "31eaf23d-b2db-4c42-9d1d-e847e75ab330",
   "status": "completed"
}

Or, if there is an error, you will see 'Invalid Code':

{
   "title": "Invalid Code",
   "type": "https://www.developer.vonage.com/api-errors/verify#invalid-code",
   "detail": "The code you provided does not match the expected value.",
   "instance": "bf0ca0bf927b3b52e3cb03217e1a1ddf"
}

At this point, your silent authentication verification is complete.