Identity verification
Stop someone from pretending to be another user to the snippet. Your server signs each user id; the snippet sends that signature with identify().
Your publishable key is public. Without verification, anyone who knows a user id could send events as that person, or read which guidance they've already seen, from the browser console.
With verification on, your server computes a userHash for the signed-in user and the page passes it to identify. Cueston checks it against your workspace's identity secret.
Set it up
Get the identity secret
In Settings → Security → Identity verification, generate the secret (it starts with iv_). Store it on your server, for example as CUESTON_IDENTITY_SECRET. It never goes to the browser.
Sign the user id on your server
userHash is the hex HMAC-SHA256 of the user id, keyed with the secret.
import { createHmac } from "node:crypto";
// Server side only. Keep the secret in an environment variable.
export function cuestonUserHash(userId) {
return createHmac("sha256", process.env.CUESTON_IDENTITY_SECRET)
.update(String(userId))
.digest("hex");
}import hashlib
import hmac
import os
def cueston_user_hash(user_id) -> str:
secret = os.environ["CUESTON_IDENTITY_SECRET"].encode()
return hmac.new(secret, str(user_id).encode(), hashlib.sha256).hexdigest()require "openssl"
def cueston_user_hash(user_id)
OpenSSL::HMAC.hexdigest("SHA256", ENV.fetch("CUESTON_IDENTITY_SECRET"), user_id.to_s)
end<?php
function cueston_user_hash($userId): string {
return hash_hmac('sha256', (string) $userId, getenv('CUESTON_IDENTITY_SECRET'));
}Pass it to identify
Cueston.identify(user.id, { role: user.role }, { userHash });
Choose how strict to be
Turn it on once your server sends userHash for every identified user.
| Mode | What happens |
|---|---|
| Off | userHash is ignored. |
| Optional | A hash is checked when it's sent. A wrong one drops the user id from events, and that user's saved state isn't returned. |
| Required | A user id needs a valid hash. Events without one are stored as anonymous, and requests for the person's saved progress are refused. |
Rotating the secret
Rotate it in the same place. You get a new secret right away, and the old one keeps working for 24 hours, so you can deploy the new one first.
Requests made with a secret API key (sk_…) come from your server and skip verification.