The verdict, field by field
Verify returns more than a pass/fail. The verdict is a small tree: a response envelope, a set of session-level claims, and a nested device block carrying the cryptographic result. Most integrations can do much more than gate on earStatus. Below is every field, and for each, how you might use it beyond the top-line verdict.
The verdict never serializes a field as null. A field is either present with a real value or omitted entirely. So "hardwareModel" in deviceis a truthful “we resolved a model” test, and the whole cohort block appears only when it was actually computed. Treat an absent field as “not determined for this attestation,” never as a value.
The response envelope
The top level of the verify response. The verdict proper lives under verdict.
| Field | Type | Meaning | Beyond the pass/fail |
|---|---|---|---|
| verdict | object | The attestation verdict (session claims + the device block, below). | The object you persist / log for an attestation event. |
| assuranceClaimsMet | string[] | The rootherald:assurance:* URNs this device satisfies (e.g. real-device, secure-boot, oem-keyed). | Capability gating without writing policy logic: required ⊆ met ⇒ allow. Drive feature flags or tiers off which claims a device meets. |
| enrollmentRequired | boolean | True only when the device isn't enrolled server-side (unknown / not activated). | The attest-first signal: enroll and retry on true; never re-enroll on a policy failure. |
verdict: session-level claims
OIDC/EAT-shaped claims describing this appraisal. On the server→server path the principal is the device, so userId is the device id and amr is the device method.
| Field | Type | Meaning | Beyond the pass/fail |
|---|---|---|---|
| acr | string (URN) | Assurance tier satisfied, e.g. urn:rootherald:device:high. | Step-up (RFC 9470): require a higher acr for sensitive actions (transfer funds, change password) than for a normal request. |
| amr | string[] | Authentication methods (RFC 8176). TPM path reads ["hwk_tpm"]. | Audit + conditional logic by method (hardware key vs. passkey fallback). |
| userId | string (uuid) | Subject id: the device UEID on this path (no user principal). | Device-bound accounts: pin an account to this silicon so a stolen session / exported cookie fails on a different device. Also the Sybil anchor. |
| authTime / expiresAt | ISO-8601 | When the attestation was appraised, and when an issued token would expire (5-min EAT lifetime). | Freshness: require a re-attest for high-value actions rather than trusting an old result. |
| requestedAcrValues | string[] | ACR values the caller asked for; empty on the named-policy path. | Echoes your step-up request back for correlation. |
verdict.device: the cryptographic result
Sourced entirely from the server-validated appraisal (the quote signature, the quote-bound event-log replay, and the resolved EAR verdict), never from a client claim.
| Field | Type | Meaning | Beyond the pass/fail |
|---|---|---|---|
| ueid | string (uuid) | Stable device identifier, derived from the endorsement-key fingerprint. | The durable key for device accounts, ban lists, and one-real-TPM-one-account Sybil defense. Survives OS reinstall + AK rotation. |
| earStatus | "affirming" | "warning" | "contraindicated" | The IETF EAR trust tier for the whole appraisal. | Graduated trust instead of a hard binary: allow on affirming, limit / step-up on warning, deny on contraindicated. |
| verdict | "pass" | "warn" | "fail" | The coarse verdict paired with earStatus. | The simplest gate if you don't want tiers. |
| attestationType | "tpm20" | "apple-se" | "android-ka" | "ios-appattest" | Which hardware root of trust produced the evidence. | Per-platform policy: accept App Attest for mobile but require tpm20 for desktop admin actions. |
| quoteVerified | boolean | The TPM quote signature verified against the enrolled AK. | The floor of every hardware claim; log it for your own audit trail. |
| secureBootVerified | boolean | A quote-bound event log established Secure Boot posture. | Workforce / BYOD posture gate: require Secure Boot for access to sensitive resources. |
| eventLogVerified | boolean | An event log was replayed and cryptographically bound to the signed quote. | Distinguishes a measured-boot device from one that only signed a bare quote. |
| platform | "windows" | "linux" | "macos" | "android" | "ios" | Device OS platform. Omitted if not resolved. | Fleet segmentation and platform-scoped rules. |
| hardwareModel | string | Finer-grained model, when resolved. Often omitted today. | Model-scoped golden-PCR reference matching and per-model policy, when populated. |
| trustworthinessVector | Record<string,int> | The AR4SI trustworthiness vector: a tier per dimension (instance-identity, configuration, executables, hardware). | Dimension-level policy: gate on the configuration or executables tier specifically, not just the overall verdict. Omitted when not appraised. |
verdict.device: cohort prevalence (optional block)
How common this device’s boot configuration is among comparable devices. The whole block is present together or omitted together; it appears only when cohort logic ran (authentic, quote-bound evidence with enough data). It is additive: an input for your own risk logic, never a RootHerald trust gate.
| Field | Type | Meaning | Beyond the pass/fail |
|---|---|---|---|
| cohortPrevalence | number [0,1] | Weakest-link prevalence: how common this device's least-common tracked boot measurement is in its cohort. | Novelty / anomaly signal. A very low prevalence is a rare config, worth extra scrutiny, a review queue, or a soft challenge. Not a score to auto-deny on. |
| cohortPrevalencePerPcr | Record<int,number> | Per-tracked-PCR prevalence breakdown (PCR index → prevalence). | Pinpoint which measurement is unusual (e.g. PCR 4 boot chain vs PCR 7 Secure Boot keys). |
| novelProfile | boolean | The boot configuration is novel: cold-start or below the prevalence floor. | Flag never-seen configs for closer review without blocking legitimate new hardware. |
| cohortScope | "global" | "tenant-fleet" | The population the prevalence was measured over. | Interpret prevalence correctly: a config rare globally may be common in your own fleet. |
| cohortKey | string (hex) | Opaque handle for this exact boot configuration. | Allowlist a known-good config so a rare-but-trusted image stops being flagged. |
| cohortSampleSize | number | Distinct-device denominator behind the prevalence. | Confidence: discount a low prevalence when the sample is still small. |
RootHerald never collapses these into a trust number, and neither should you gate solely on them. Use the explicit checks (earStatus, posture booleans, assuranceClaimsMet) as the decision, and cohort prevalence as an additional input to routing, review, or step-up.
A full example
A verify response for an affirming Windows TPM device (null fields omitted):
{
"verdict": {
"acr": "urn:rootherald:device:high",
"amr": ["hwk_tpm"],
"authTime": "2026-07-03T17:08:13Z",
"expiresAt": "2026-07-03T17:13:13Z",
"userId": "1ade0832-6a16-cf50-a2bd-2a5c4cb498a5",
"requestedAcrValues": [],
"device": {
"ueid": "1ade0832-6a16-cf50-a2bd-2a5c4cb498a5",
"earStatus": "affirming",
"verdict": "pass",
"attestationType": "tpm20",
"attestedAt": "2026-07-03T17:08:13Z",
"quoteVerified": true,
"secureBootVerified": true,
"eventLogVerified": true,
"platform": "windows",
"trustworthinessVector": {
"instance-identity": 2, "configuration": 2, "executables": 2, "hardware": 2
},
"cohortPrevalencePerPcr": { "0": 1, "4": 1, "7": 1 },
"novelProfile": true
// hardwareModel, cohortPrevalence, cohortScope, cohortKey, cohortSampleSize:
// omitted here — not resolved / not enough cohort data for this device.
}
},
"assuranceClaimsMet": [
"rootherald:assurance:real-device",
"rootherald:assurance:secure-boot",
"rootherald:assurance:oem-keyed"
],
"enrollmentRequired": false
}