DID documents
A verifier resolves two DID documents to check a receipt: the company document
for companySig, and the citizen document for the WebAuthn assertion. They
use different DID methods and expose keys differently.
The company DID document
Resolved from did:web:agreely.ca:c:{slug} at
https://agreely.ca/c/{slug}/did.json. It resolves only when the company has a
verified domain and an active signing key.
{
"@context": [
"https://www.w3.org/ns/did/v1",
"https://w3id.org/security/data-integrity/v2"
],
"id": "did:web:agreely.ca:c:acme",
"alsoKnownAs": ["did:web:acme.com"],
"verificationMethod": [
{
"id": "did:web:agreely.ca:c:acme#kms-1",
"type": "Multikey",
"controller": "did:web:agreely.ca:c:acme",
"publicKeyMultibase": "z6Mk...base58btc..."
}
],
"assertionMethod": ["did:web:agreely.ca:c:acme#kms-1"],
"authentication": ["did:web:agreely.ca:c:acme#kms-1"]
}
| Field | Meaning |
|---|---|
id |
The Agreely-hosted company DID. |
alsoKnownAs |
The company's verified real domain DID, the binding that proves the Agreely-hosted id belongs to the real organization. |
verificationMethod[].type |
Multikey. |
verificationMethod[].publicKeyMultibase |
The Ed25519 public key as z-prefixed base58btc of `(ed25519-pub multicodec 0xed01 |
assertionMethod / authentication |
Reference the signing key fragment. |
The citizen DID document
Resolved from did:agreely:citizen:.... It is public, unauthenticated, and
tenant-less by design (any verifier may resolve it). It is assembled from the
full key history, so every key the DID ever held appears with its authority
window.
{
"@context": [
"https://www.w3.org/ns/did/v1",
"https://w3id.org/security/suites/ed25519-2020/v1"
],
"id": "did:agreely:citizen:9F8K2M4P7Q1R3T5V8W0X2Y4Z6B",
"verificationMethod": [
{
"id": "did:agreely:citizen:9F8K2M4P7Q1R3T5V8W0X2Y4Z6B#passkey-1",
"controller": "did:agreely:citizen:9F8K2M4P7Q1R3T5V8W0X2Y4Z6B",
"validFrom": "2026-01-10T14:00:00Z",
"validUntil": null,
"type": "WebAuthnAuthenticationKey2024",
"publicKeyCose": "0xa5010203262001..."
},
{
"id": "did:agreely:citizen:9F8K2M4P7Q1R3T5V8W0X2Y4Z6B#recovery-1",
"controller": "did:agreely:citizen:9F8K2M4P7Q1R3T5V8W0X2Y4Z6B",
"validFrom": "2026-01-10T14:00:00Z",
"validUntil": null,
"type": "Ed25519VerificationKey2020",
"publicKeyMultibase": "z6Mk...base58btc..."
}
],
"authentication": [
"did:agreely:citizen:9F8K2M4P7Q1R3T5V8W0X2Y4Z6B#passkey-1"
],
"capabilityInvocation": [
"did:agreely:citizen:9F8K2M4P7Q1R3T5V8W0X2Y4Z6B#recovery-1"
]
}
| Field | Meaning |
|---|---|
validFrom / validUntil |
The key's authority window. validUntil is present even when null so a verifier distinguishes "still valid" from "expired at T". A receipt signed at time T resolves to whichever key was authoritative at T. |
WebAuthnAuthenticationKey2024 |
A passkey. Its publicKeyCose is the COSE-encoded public key as 0x-hex; verify the receipt's WebAuthn assertion against it. |
Ed25519VerificationKey2020 |
A recovery key, exposed as publicKeyMultibase. |
authentication |
Passkey fragments (authorized to sign consent). |
capabilityInvocation |
Recovery-key fragments, authorized solely for DID rotation, never for signing consent. |
The window is what keeps old receipts valid
When you verify proof[1] of a receipt, take its verificationMethod fragment, find that method in the citizen document, and confirm its [validFrom, validUntil] window contains the receipt's grantedAt. Then verify the assertion against that method's COSE key. A rotated-out key still verifies its historical receipts.
Next
- Verify a receipt ties both documents into the four-check recipe.