Skip to content
Registry StackDocsv0.46.0

Manage verifier trust

For the consumer or verifier

View as Markdown

If you operate an application that verifies Evidence responses, its verifier must trust provider keys your organization approved, never keys the service or the response supplies while it is being verified. You pin the provider’s public keys, keep a revoked key out, and take the provider’s signing-key rotation without a gap.

Obtain each public JWK from the provider through your onboarding channel, not from its JWKS endpoint alone, then assemble the set your client will trust:

Terminal window
rstack evidence jwks \
--output trusted-jwks.next.json \
provider-current.public.jwk.json \
provider-next.public.jwk.json
wrote trusted-jwks.next.json

The command refuses a private key and an existing output file; pass --force to overwrite. Write each set to a new file and activate it through your configuration change process, so the previous set stays available for rollback.

Pass the set to rstack evidence client profile create with --pinned-jwks, a path relative to the profile file. The other values are the ones your deployment’s operator gave you; the private key is the one your client registered with the issuer:

Terminal window
rstack evidence client profile create \
--base-url https://evidence.example.com \
--client-id age-check-app \
--private-key-file app-key/client-assertion-p384-private-jwk \
--pinned-jwks trusted-jwks.json \
--output age-check-client.json
Created client profile

rstack evidence keygen client-assertion --output-dir app-key writes a key of that name (ES384, its default); register its public half with your issuer. Without --pinned-jwks the profile fetches the service’s key set itself, over HTTPS discovery or, with --local-loopback-discovery, over loopback. A profile carries no revoked-key list in any trust mode, so with a profile you revoke a key by removing it from the pinned set.

When you need revoked key ids beside the pinned set, construct the client yourself:

client = EvidenceClient(
"https://evidence.example.com",
trusted_jwks=json.loads(Path("trusted-jwks.json").read_text()),
revoked_key_ids=["<revoked kid>"],
token=token_config,
)

In Node, the same configuration takes trustedJwks and revokedKeyIds. A revoked key id is refused even while the key is still in the pinned set.

  1. When the provider announces a new key, add it to the pinned set and activate the set before the provider signs with it.
  2. Once the provider’s maximum assertion lifetime plus clock skew has passed since the old key last signed, remove the old key from the set. With an explicit client, also add its key id to revoked_key_ids if it was compromised.

A response signed by a key outside the set fails with code key. Treat that as a trust change to approve, never as a key to fetch. Rotation does not touch decisions you already kept: each retained verification carries the keys trusted when its request was sent, so a replay reads no current key set. The provider’s side is Rotate Registry Evidence signing keys.

Registry Evidence security model, for the threats pinning answers.