Integrations

Node.js

Server-side steps in Node.js.

Prerequisites

  • Node.js with the built-in crypto module and fetch.
  • The secret key of the scenario and a permanent API token, read from environment variables. Never put them in browser code or in a repository.
  • The API address provided with your access.

The call sequence

  1. Your server encrypts the raw client key with the secret key of the scenario.
  2. Your page opens the widget with the scenario identifier and the encrypted client key.
  3. The user completes the steps in the widget.
  4. Your server learns of the result from the SESSION_COMPLETE webhook, or reads session status.
  5. Your server decides on the customer from the server-side status.

Encrypt the client key

The secret key of the scenario never leaves your server. See working with clientKey for the algorithm.

const crypto = require("crypto");

function encryptClientKey(clientKeyRaw, secret) {
  // First 32 characters of the SHA-256 hash of the secret, written as hex.
  const key = crypto.createHash("sha256").update(secret).digest("hex").substring(0, 32);
  const iv = crypto.randomBytes(16);
  const cipher = crypto.createCipheriv("aes-256-cbc", key, iv);
  const encrypted = Buffer.concat([cipher.update(clientKeyRaw, "utf8"), cipher.final()]);
  return Buffer.concat([iv, encrypted]).toString("base64");   // the clientKey for the widget
}

module.exports = { encryptClientKey };

A route that serves the key

const express = require("express");
const { encryptClientKey } = require("./encrypt");

const app = express();

app.post("/verification/start", (req, res) => {
  const clientKeyRaw = `${req.user.id}`;                 // your own identifier, at most 36 characters
  const clientKey = encryptClientKey(clientKeyRaw, process.env.SCENARIO_SECRET_KEY);
  res.json({ clientKey });
});

Store the raw value with your user or order, so that you can match the result later.

Create a session from the server

You can also create a session with the REST API and read it back. See create session.

async function createSession() {
  const reply = await fetch(`${process.env.API_BASE_URL}/kyc/session/create`, {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({
      token: process.env.API_TOKEN,              // permanent API token
      schemaId: process.env.SCENARIO_ID,         // scenario identifier
    }),
  });
  const body = await reply.json();
  if (!body.sessionId) {
    // A failure arrives as a body with status "error" or "failed".
    throw new Error(`session was not created: ${body.status}`);
  }
  return body;                                   // body.status is the session status, "idle"
}

Read the result

async function sessionStatus(sessionId) {
  const reply = await fetch(`${process.env.API_BASE_URL}/kyc/session/status`, {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({ token: process.env.API_TOKEN, sessionId }),
  });
  return reply.json();                           // branch on body.status
}

Branch on status, never on message text. See response format and errors and session statuses.

Troubleshooting

SymptomWhat to check
The widget does not openThe domain is in the allowed domains, the page is on HTTPS, and the widget is not inside a cross-origin iframe. See installation.
The widget reports that decryption failedThe client key was not encrypted, or a different secret key was used, or the string was cut. See working with clientKey.
A call returns success but the body has an errorBranch on the status field of the body. See response format and errors.
The result never reaches your serverCheck the callback URL in the scenario. See webhooks.

Next: receive the result

Set up a webhook endpoint on your backend.

Receiving webhooks