How grading works

Every check result is deterministic: given the same directory and response headers, the checker always produces the same verdict and grade.

3-state verdict

The verdict has exactly three possible values:

  • VALID - the directory exists, all keys are structurally valid (kty, crv, and a 32-byte x), and no private key material (d) is present. A custom kid label is fine; the verdict does not depend on it.
  • INVALID - a directory was found at the well-known path, but at least one critical check failed: private d present, a malformed Ed25519 key (x not 32 bytes), or the Ed25519 signature does not verify. A key of another type or curve does NOT make the directory invalid: the drafts permit other registered algorithms, so such keys only raise advisory warnings.
  • NOT FOUND - no usable directory at the well-known path: non-2xx HTTP response, response body is not JSON, the key set is empty, or the host is unreachable (including DNS failure).

Letter grade

The letter grade (A through F) is only shown when a directory exists (verdict is VALID or INVALID). There is no letter grade for NOT FOUND.

The grade is derived from a weighted score that starts at 100 and subtracts points for each failed or warned check.

Scoring weights

TierFail deductionWarn deduction
JWKS directory-25 per fail-6 per warn
RFC 9421 signature-30 per fail-8 per warn
Agent Card (advisory)-6 per fail-2 per warn

Letter thresholds

LetterMinimum score
A90 or above
B75 to 89
C60 to 74
D40 to 59
Fbelow 40, or capped (see below)

Grade capping rules

Certain critical failures impose a hard ceiling on the grade regardless of the raw score:

  • Private key material present in the directory - grade is capped to F.
  • Ed25519 signature fails to verify - grade is capped to a maximum of D.
  • Directory not served over HTTPS - grade is capped low (treated as a critical failure).

Agent Card checks are advisory

Checks in the Agent Card tier nudge the score and can raise warnings, but they never change the verdict and never trigger a grade cap. A missing or incomplete Agent Card will lower the score slightly; it will not cause a VALID directory to become INVALID.

What is checked

JWKS directory checks

  • Directory is served over HTTPS
  • Directory URL returns HTTP 200
  • Response media type. The web-bot-auth type (application/http-message-signatures-directory+json) passes. Another valid JWKS type such as application/jwk-set+json or a generic application/json is accepted but raises a warning, because web-bot-auth asks for its own media type. A non-JSON type such as text/html, or a missing media type, is a failure.
  • Response body is valid JSON
  • Key set has the expected shape (keys array)
  • Key set is non-empty
  • Key set size is within reasonable bounds
  • Caching headers are present
  • Directory response self-signature: the draft recommends the response carries one signature per key (tag http-message-signatures-directory). Absent warns, valid passes, present-but-broken fails. Advisory either way: never a cap, never a verdict change.
  • Per-key: kty=OKP (advisory: another type warns, because the drafts permit other registered algorithms while Ed25519 remains the deployed baseline)
  • Per-key: crv=Ed25519 on OKP keys (advisory: another curve warns)
  • Per-key: x is 32 bytes (base64url-encoded), evaluated on Ed25519 keys
  • Per-key: the RFC 7638 thumbprint is computed and shown. This is the value a verifier matches an incoming signature’s keyid against. The JWK kid member itself is a free-form label, so a custom kid is allowed and only the signature’s keyid has to be a thumbprint. This check is informational and never lowers the grade.
  • Per-key: no private key material (d not present)
  • No duplicate kid values in the set
  • Validity window (if present) is plausible

RFC 9421 signature checks

  • Signature-Agent header present and well-formed (dictionary form, or the legacy string form with a note)
  • Signature-Input parses correctly
  • Covered components include @authority or @target-uri, plus signature-agent whenever the header is sent
  • Required signature parameters present
  • tag=web-bot-auth
  • created and expires within allowed clock skew
  • Validity window within the draft-recommended 24 hours (advisory)
  • keyid resolves to a key in the directory
  • Ed25519 signature verifies against the resolved key (a signature made with another registered algorithm warns as “not verifiable by this checker yet” instead of failing)
  • Replay advisory: passes when the recommended nonce is present, warns when absent

Agent Card checks (advisory)

  • client_name present
  • client_uri present
  • contacts present
  • jwks_uri present
  • purpose present
  • RFC 9309 robots.txt compliance declaration
  • Rate expectation declared