Skip to content

Server-side validation

After the user completes the challenge, the widget will return a response token, which must be validated by your backend to ensure the user is not using an anonymization service.

The response will only be considered valid once and must be verified using the secret key, in the next 5 minutes after its issuance.

Validate the response

To validate the response you have to send a POST request to the following endpoint:

bash
$ curl -X POST 'https://challenges.v4guard.io/checkpoint/v2/tokenverify' --data 'secret=SECRET_KEY&token=RESPONSE_TOKEN'
javascript
const { URLSearchParams } = require("url");
const fetch = require("node-fetch");
const encodedParams = new URLSearchParams();

encodedParams.set("secret", "SECRET_KEY"); 
encodedParams.set("token", "RESPONSE_TOKEN"); 

let url = "https://challenges.v4guard.io/checkpoint/v2/tokenverify";

let options = {
  method: "POST",
  headers: { "Content-Type": "application/x-www-form-urlencoded" },
  body: encodedParams,
};

fetch(url, options)
  .then((res) => res.json())
  .then((json) => console.log(json))
  .catch((err) => console.error("error:" + err));
php
<?php

$curl = curl_init();

curl_setopt_array($curl, [
  CURLOPT_URL => "https://challenges.v4guard.io/checkpoint/v2/tokenverify",
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_ENCODING => "",
  CURLOPT_MAXREDIRS => 10,
  CURLOPT_TIMEOUT => 30,
  CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
  CURLOPT_CUSTOMREQUEST => "POST",
  CURLOPT_POSTFIELDS => "secret=SECRET_KEY&token=RESPONSE_TOKEN", 
  CURLOPT_HTTPHEADER => [
    "Content-Type: application/x-www-form-urlencoded"
  ],
]);

$response = curl_exec($curl);
$err = curl_error($curl);

curl_close($curl);

if ($err) {
  echo "cURL Error #:" . $err;
} else {
  echo $response;
}
python
import requests

url = "https://challenges.v4guard.io/checkpoint/v2/tokenverify"

payload = "secret=SECRET_KEY&token=RESPONSE_TOKEN" // [!code focus] // [!code hl]
headers = {"Content-Type": "application/x-www-form-urlencoded"}

response = requests.request("POST", url, data=payload, headers=headers)

print(response.text)

To see an example response from the endpoint, check the Validation parameters section.

Feel free to check out our complete demo on GitHub to see a complete integration of the Checkpoint widget, and the server-side validation.

Validation parameters

The validation endpoint accepts the following parameters:

ParameterRequired/OptionalDescription
secretRequiredThe secret key generated for your site/secret keypair.
tokenRequiredThe response token provided by the widget upon completion of the challenge.
remote_addrOptionalThe IP address of the user, which will be used to validate the integrity of the challenge.

NOTE

If sent, the remote_addr parameter will help prevent possible challenge abuses by ensuring the user's IP address matches the one used to complete the challenge, if they don't match, the endpoint will return a non-successful operation.

The tokenverify endpoint only accepts application/x-www-form-urlencoded requests, and the response will be in application/json format. It will always return a success property which can be either true or false and will indicate if the verification operation was successful or not.

An example of a successful response should be similar to the following:

json
{
  "success": true, 
  "response": {
    "challenge_id": "85f27dfb754da922",
    "trace_id": "18f58dabe7b5361d",
    "domain": "v4guard.me",
    "blocked": false,
    "action": "signup",
    "remote_addr": "31.6.16.13",
    "timestamp": "2023-05-24T12:06:50+02:00"
  }
}

As you can see, the response will contain the following properties:

  • challenge_id: The challenge ID used to complete the challenge.
  • trace_id: The trace ID linked to the check request made by the widget.
  • domain: The hostname of the site where the widget was invoked.
  • blocked: A boolean value indicating if the user must be blocked or not due to anonymization service usage.
  • action: If specified in widget invocation, this will be the user's defined field. This is also used to display different actions and differentiate widgets on the same sitekey on the Checkpoint analytics.

    This field should be validated in order to ensure it's integrity, and avoid modifications from the client-side.
  • remote_addr: The IP address of the user that completed the challenge.
  • timestamp: The ISO timestamp for the time the challenge was issued and completed.

If the validation fails, the response will be similar to the following:

json
{
  "success": false, 
  "errors": [
    "INVALID_TOKEN"
  ]
}

Error Codes

This are the possible error codes that can be returned by the token verification endpoint in case of a non-successful operation:

Error CodeDescription
MISSING_SECRETThe secret parameter is missing from the request.
MISSING_TOKENThe token response parameter is missing from the request.
INVALID_SECRETThe secret parameter is invalid.
INVALID_TOKENThe token response parameter is invalid. Either it's malformed, not valid for the given secret, has expired or has already been validated.
REMOTE_ADDR_MISMATCHThe remote_addr parameter was sent, but it doesn't match the IP address used to complete the challenge.