Skip to content
SDKs · NodeAvailableView source

@rootherald/node

The server-side SDK. Appraise an opaque evidence blob server→server with rh.verify() and get the AttestationVerdict back directly in the response.

Install

npmbash
npm install @rootherald/node

Appraise evidence (Background-Check default)

The default RATS Background-Check flow: your keyless client collects an opaque evidence blob and hands it to your server; your server calls Root Herald server→server with its rh_sk_ secret key. Two calls (mint a challenge, then appraise), and the verdict comes back directly with no token to verify.

app/api/signup/route.tsts
import { RootHerald, QuotaExceededError } from "@rootherald/node";

const rh = new RootHerald({ secretKey: process.env.RH_SECRET_KEY! }); // rh_sk_…

// (a) GET /api/challenge — mint a nonce and relay it to your client.
export async function GET() {
  const { challengeId, nonce } = await rh.issueChallenge();
  return Response.json({ challengeId, nonce });
}

// (b) POST /api/signup — the client posts back the opaque evidence; appraise it.
export async function POST(req: Request) {
  const { challengeId, evidence, email, password } = await req.json();

  let verdict;
  try {
    verdict = await rh.verify(evidence, {
      challengeId,
      policy: "rootherald:builtin:strict-hardware",
    });
  } catch (err) {
    // Throws only on protocol/auth/quota problems, not on a failing device.
    if (err instanceof QuotaExceededError) {
      return Response.json({ error: "rate_limited" }, { status: 429 });
    }
    throw err;
  }

  // A real-but-rejected device returns a verdict; branch on device.verdict.
  if (verdict.device.verdict !== "pass") {
    return Response.json({ error: "device_rejected" }, { status: 403 });
  }

  // verdict.device.ueid is a stable device UUID. Use it for
  // one-device-one-account enforcement.
  if (await usersRepo.deviceAlreadyRegistered(verdict.device.ueid)) {
    return Response.json({ error: "device_already_registered" }, { status: 409 });
  }

  const user = await usersRepo.create({
    email,
    password,
    deviceId: verdict.device.ueid,
  });
  return Response.json({ ok: true, userId: user.id });
}