Integrations
Node.js
Server-side steps in Node.js.
Prerequisites
- Node.js with the built-in
cryptomodule andfetch. - 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
- Your server encrypts the raw client key with the secret key of the scenario.
- Your page opens the widget with the scenario identifier and the encrypted client key.
- The user completes the steps in the widget.
- Your server learns of the result from the
SESSION_COMPLETEwebhook, or reads session status. - 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
| Symptom | What to check |
|---|---|
| The widget does not open | The 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 failed | The 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 error | Branch on the status field of the body. See response format and errors. |
| The result never reaches your server | Check the callback URL in the scenario. See webhooks. |