Skip to content

How it works

Five steps, cryptographically grounded.

Your side is simple: your app collects a sealed proof from the device, and your server asks us for a pass / warn / fail answer. Everything in between is what earns that answer. We confirm the proof came from genuine hardware, then match it to your rules. Here is every step, plain first, with the code and the internals underneath.

Step 1

Your app collects a sealed proof from the device's chip

Virtually every modern laptop and phone has a small security chip built in: a TPM on Windows and Linux, a Secure Enclave on Apple hardware. Our SDK asks that chip for a fresh, sealed proof that the request is coming from a specific, real, physical machine. Not a script. Not a rented cloud server. (Today that runs through the native client, or the Root Herald browser extension, which is in preview and not yet in the browser stores.) That act, the device cryptographically proving what it is, is what we mean by attestation.

This is the only work that happens on the user's device, and it stays completely hands-off. The client holds none of Root Herald's keys and makes no decision. It hands the sealed proof back to your app, tied to the action you care about (signup, claim, vote, game-launch, or your own label). Your app forwards it to your server with the rest of the request, and your server asks us for the verdict.

native client (C/C++)cpp
// Collect a fresh, sealed proof from the device's security chip,
// bound to a one-time challenge from your server. The client
// consults no key and renders no verdict.
char* evidence = nullptr;
RootHeraldClient_CollectEvidence(nonce, &evidence);
// Hand the opaque `evidence` blob to your backend to check (step 5).
RootHeraldClient_FreeEvidence(evidence);

// On the web, the extension collects the same opaque proof; your
// backend checks it with @rootherald/node (see step 5).

Step 2

The chip signs a one-time challenge

Before it trusts anything, your server hands the device a one-time challenge code (a nonce), and the chip signs that exact code. This is what keeps the proof fresh: a proof captured yesterday, or copied off another machine, carries the wrong challenge and is thrown out. You get a proof made for this request, not a recording someone can replay.

Windows and Linux ship today. Mobile and macOS are coming: on Android, Hardware Key Attestation; on iOS, App Attest; on macOS, the Secure Enclave at a reduced level of assurance.

For engineers

On Windows / Linux the SDK talks to a local native host over the extension's native-messaging API. The host issues a TPM2_Quote over PCRs 0–7 under the server nonce, reads the EK public key and certificate off the chip, and pulls any missing intermediate certificates from the Windows TPM store, Intel PTT NV handles, or the AMD fTPM AIA endpoint as needed.

Step 3

We confirm the proof came from genuine hardware

A software fake can call itself anything, but it cannot forge a real chip manufacturer's signature. So we trace the proof back to the manufacturer that made the chip and confirm that manufacturer is on our trust anchorlist: the short list of chip makers we're willing to believe. This is the line between a genuine device and a rented cloud server or software emulator pretending to be one.

If the manufacturer's signature checks out, the proof is real hardware. If a piece of it is genuinely just unreachable for a moment, we retry; if it doesn't trace back to a trusted manufacturer, we reject it outright and never retry.

For engineers

EkCertificateValidator walks the EK certificate chain. When intermediates are missing, AiaChaser follows AIA URLs (up to 16 levels) backed by a Postgres + in-memory cache with stale-while-revalidate, and the chain must terminate at one of our pinned manufacturer roots. ChainFailureKind separates operational failures (EkChainFetchFailed, retry-eligible) from cryptographic ones (EkNotTrusted, EkKeyMismatch, never retried).

Step 4

We check it against your rules

A policy is your rule for how strict to be: accept real hardware only, or allow cloud devices too. Different products draw that line in different places, so you pick the rule and we enforce it on every check.

Five built-in policies cover most needs (strict-hardware, strict-hardware-permissive-mobile, cloud-permissive, enterprise-managed-only, and dev), or you can author your own. When you choose to allow cloud devices, we don't take their word for it. We bind the proof to a specific cloud instance and reject anything that doesn't match.

For engineers

PolicyResolver picks the policy by three-rung resolution: per-call → per-session → per-project default → strict-hardware fallback. For cloud-permissive policies the cross-validators run here — NitroTPM + EC2 instance identity, Azure IMDS-attested data, and the GCP instance-identity JWT each bind the cloud vTPM to one specific instance. A mismatch rejects with the audit event cloud_cross_validation_failed.

Step 5

You get a pass, warn, or fail — plus an anonymous device ID

Your server makes one server-to-server call, and gets back a verdict: a pass / warn / fail answer plus an anonymous per-device ID. There's no token to store and no state to keep. The device ID is stable per chip for you, but can't be correlated to any other company. So you learn “is this the same device as last time?” with no tracking cookie and no personal data.

server · @rootherald/nodets
const rh = new RootHerald({ secretKey: process.env.RH_SECRET_KEY }); // rh_sk_…
const { challengeId, nonce } = await rh.issueChallenge(); // relay nonce to client
const verdict = await rh.verify(evidence, {               // check it server→server
  challengeId,
  policy: "rootherald:builtin:strict-hardware",
});

// verdict ≈ AttestationVerdict
{
  "acr": "urn:rootherald:device:high",
  "device": {
    "ueid": "2f9c8a14…",                  // stable per-company device id (no PII)
    "verdict": "pass",                    // pass | warn | fail
    "earStatus": "affirming",             // affirming | warning | contraindicated
    "attestationType": "tpm20",
    "secureBootVerified": true,
    "trustworthinessVector": { "hardware": 2, "configuration": 2 }
  }
}

What you get out

The contract.

Whatever your branching logic (allow / friction / deny / step-up / rate-limit / grant-credits), the contract is the same: pass the anonymous device.ueid into your existing business logic, store it as the per-company device pseudonym, and you have a hardware-rooted identity layer under whatever you build next.

See the whole flow run on your own device.

Free up to 10K device checks a month, no card.