Skip to content

The product

One interface. Every device.

A TPM, a Secure Enclave and an Android TEE prove different things, in different formats, against different roots of trust. Root Herald puts all of them behind one call — and returns one verdict shape, whatever the device turned out to be.

The integration

This is the whole thing.

your backendts
const result = await rh.verify({
  challengeId: req.body.challengeId,
  evidence:    req.body.evidence,
});

if (result.verdict.device.verdict !== "pass") {
  return res.status(403).json({ error: "device_check_failed" });
}

You never parse a quote, walk a certificate chain, or learn what a PCR is. The evidence arrives from the device as an opaque blob, your server relays it, and the answer comes back.

The same call handles a Windows laptop with a discrete TPM and an iPhone using App Attest. Nothing in your code says which.

Coverage

Five attestation technologies, one contract.

PlatformRoot of trustWhat it proves
WindowsTPM 2.0Quote over a nonce + EK certificate chain to the chip vendor
LinuxTPM 2.0Quote over a nonce + EK certificate chain to the chip vendor
AndroidTEE / StrongBoxKey Attestation chain to Google's hardware root
iOSSecure EnclaveApp Attest chain to Apple's attestation root
macOSSecure EnclavePossession of a non-exportable key

The desktop SDKs expose a byte-identical C ABI, so the same integration code links on all three. Where a platform genuinely proves less — macOS cannot currently prove its own silicon — the verdict says so rather than papering over it. What each platform can prove →

Why one call is enough

Ask for a capability, not an operating system.

You declare what the action requires. The verdict lists what the device actually proved. Allowed when the first is a subset of the second.

This is what keeps the integration from rotting: add a platform, or a platform gains a capability it lacked, and the claim simply starts appearing. No branch to update, no version check, no redeploy.

capability, not platformts
const REQUIRED = ["rootherald:assurance:real-device"];

const met = new Set(result.assuranceClaimsMet);
const allowed = REQUIRED.every((c) => met.has(c));

What you don't build

The part that takes months.

Signature and freshness

TPM2_Quote parsed and verified against the enrolled attestation key, with the nonce read from inside the signed structure — not from a field alongside it.

Certificate chains

Endorsement-key chains validated to seeded chip-vendor roots, with revocation and vendor-specific intermediates handled per manufacturer.

Measured boot

The TCG event log replayed and bound to the signed quote, so boot state is only trusted when the replayed PCRs match the ones the chip signed.

Mobile attestation

Android Key Attestation and Apple App Attest validated against their own roots, with the security level read from the certificate rather than claimed by the app.

Cloud and emulator classing

Provider vTPMs and software emulators identified as what they are, so a rented server can't present itself as a laptop.

Policy resolution

Your acceptance rules applied server-side and changed without a redeploy, so tightening a policy doesn't mean shipping code.

How attestation works, in full →quote construction, EK chain validation, policy resolution

Getting it

Where the contract reaches today.

The API

One HTTPS endpoint, one contract, one set of error codes. Usable directly from any language that can post JSON — an SDK is convenience, never a requirement.

SDKs

@rootherald/node is available today; the rest are rolling out. Because the wire contract is published and stable, a binding landing later doesn't change code you've already written.

Status for every language →

Dashboard

Usage, API keys, the policy editor, a live event tail, and billing.

One call, one verdict.

Free up to 1,000 active devices a month, no card.