PKA Endpoint Proof
Implementer reference for AID v2 Public Key for Agent endpoint proof.
PKA Endpoint Proof
Public Key for Agent (PKA) is AID's optional endpoint-proof profile. It lets a client verify that the endpoint discovered from DNS controls the Ed25519 private key matching the public key in the selected AID record.
PKA proves endpoint key possession. It does not authenticate a user, authorize an action, issue a token, prove workload identity, or describe capabilities.
For the normative protocol text, see Specification Appendix B. This page expands that appendix into an implementer checklist.
Inputs
A verifier starts with a selected aid2 record:
v=aid2;u=https://api.example.com/mcp;p=mcp;k=ebVWLo_mVPlAeLES6KmLp5AfhTrmlb7X4OORC60ElmQ
The k value is the unpadded base64url Ed25519 JWK x member. It must decode to exactly 32 bytes.
The matching JWK shape is:
{ "kty": "OKP", "crv": "Ed25519", "x": "<k>" }
Derived Key Identity
For aid2, DNS does not publish kid or i. The expected HTTP signature keyid is derived from k with RFC 7638.
Hash this exact UTF-8 JSON serialization:
{"crv":"Ed25519","kty":"OKP","x":"<k>"}
Then encode the SHA-256 digest as unpadded base64url. Do not hash the raw public key bytes directly.
For the example key above, the expected keyid is:
WWpn_pfHui9YKR4CZtQsDGMu7_Gch2zYChfSvnxgtPk
Verifier Algorithm
- Decode
kas unpadded base64url and require 32 bytes. - Derive the expected RFC 7638 JWK thumbprint from
k. - Generate a nonce with at least 32 bytes of entropy. Unpadded base64url is recommended for transport.
- Send a PKA request to the discovered
uvalue. Remove fragments, preserve query strings, and do not follow redirects. - Include
Accept-Signaturerequesting the AID profile shown below. - Include
Cache-Control: no-store. - Parse
Signature-InputandSignaturefrom the response. - Require the covered components,
tag,keyid,alg,nonce,created,expires, and responseCache-Controlrules below. - Reconstruct the RFC 9421 signature base from the received Structured Field values.
- Verify the Ed25519 signature with the public key from DNS
k.
Request And Response
Client request header:
Accept-Signature: aid-pka=("@method";req "@target-uri";req "@authority";req "@status");created;expires;keyid="<jwk-thumbprint>";alg="ed25519";nonce="<client-challenge>";tag="aid-pka-v2"
Cache-Control: no-store
Server response headers:
Signature-Input: aid-pka=("@method";req "@target-uri";req "@authority";req "@status");created=<unix>;expires=<unix>;keyid="<jwk-thumbprint>";alg="ed25519";nonce="<client-challenge>";tag="aid-pka-v2"
Signature: aid-pka=:<base64-signature>:
Cache-Control: no-store
The signature must not cover HTTP Date.
Covered Components
The AID v2 PKA signature covers exactly:
"@method";req"@target-uri";req"@authority";req"@status"
@method, @target-uri, and @authority are request-derived and therefore use ;req. @status is response-derived and does not use ;req.
A signed non-200 status can still prove endpoint authenticity. For example, a signed 401 can prove the endpoint before the OAuth or auth.md layer continues.
URI And Authority
The request context is based on the discovered endpoint URI:
- remove the fragment;
- preserve the query string;
- lowercase the hostname;
- omit default ports;
- retain non-default ports;
- reject redirects during PKA verification.
Servers behind reverse proxies must sign the externally visible request context, not internal hop-local host, scheme, or port values.
Freshness And Caching
created and expires are mandatory.
expiresmust be greater thancreated.expires - createdmust not exceed 300 seconds.expires - createdshould be 60 seconds or less.- Verifiers may allow small clock skew.
- The received
noncemust exactly match the verifier's challenge. - PKA requests and responses use
Cache-Control: no-store.
Servers do not need nonce storage in v2 core because the verifier supplies a one-shot nonce, the response is short-lived, and the response is not cacheable.
Rejection Checklist
Reject the PKA response when any of these are true:
- the selected record is not
aid2; kis missing, padded, not base64url, or not 32 decoded bytes;- the response follows a redirect;
Signature-InputorSignatureis missing or malformed;- covered components differ from the AID profile;
tagis notaid-pka-v2;keyiddiffers from the RFC 7638 thumbprint derived from DNSk;algis not semanticallyed25519;noncediffers from the challenge;createdorexpiresis missing or outside the freshness policy;- response
Cache-Control: no-storeis missing; - Ed25519 verification fails over the reconstructed signature base.
Canonical Test Vector
The repository ships a canonical vector at protocol/pka_vectors.json with id v2-rfc9421-response-signature. It includes the aid2 record, k, derived JWK thumbprint, nonce, request headers, response headers, signature base, and Ed25519 signature.
Use that vector before claiming independent PKA compatibility.
Legacy Aid1 Compatibility
Legacy aid1 PKA remains available only for compatibility clients during the migration window. It uses k=z... base58btc, requires i/kid, carries the challenge through AID-Challenge, and includes HTTP Date in the legacy covered set.
Do not apply those legacy rules to aid2 records.
See Also
- Identity & PKA
- Security
- Specification Appendix B
- aid-doctor CLI
- External Identity Anchors - historical background, pre-v2 wire format