DID Management

Managing your DID document.

Your did.json is your public identity — the file every verifier reads to check your seals. Keeping it current is your responsibility.

Your DID document is a JSON file on your website. It contains your public keys — the keys verifiers use to check your signatures. If it's stale, missing, or out of sync with your local keys, verification fails.

New to this? Sign & Verify explains what the seal does and why it matters. This page is about the housekeeping behind it: keeping the keys published and current.

You own this file.

Whether you use the TrustDID managed dashboard or host everything yourself, the did.json on your domain is the authoritative source of truth. It's your responsibility to keep it current — just like keeping your website's TLS certificate or DNS records up to date. TrustDID provides tools to make this easy.

What triggers an update?

Your did.json needs to be re-deployed whenever the public keys change. The common triggers:

Key rotation
Annual rotation, or after a suspected compromise
New profile
Added a department, staff member, or server profile
Profile removed
Staff departure, department restructured
PQ key added
Post-quantum key added to an existing profile
DNSSEC update
DNS anchor changed or zone re-signed
Trust registry
Registry membership or endpoint changed

Two modes of operation

Managed (dashboard)

TrustDID's dashboard stores your DID and provides a download bundle, API access, and audit logging.

When you rotate keys or add profiles, the updated DID is automatically pushed to the dashboard. You then deploy to your domain.

You still deploy to your website. The dashboard is staging; your domain is production.

Self-managed

You control everything. Your did.json lives on your web server. TrustDID generates and signs the file locally; you deploy it manually.

No API dependency. Full sovereignty. But you're responsible for keeping the published file in sync.

What the dashboard provides

For managed-mode users, the TrustDID dashboard is your control centre.

ZIP bundle download

Download a ZIP that mirrors your web server structure: .well-known/did.json plus any public/{profile}/did.json files. Extract to your domain root and you're done.

Audit log

Every change is logged: DID pushes, profile additions, key rotations, bundle downloads. Timestamp, action, and detail for every operation.

Token management

Rotate or revoke API tokens from the dashboard. Per-token access control for different machines and automation scripts.

API access

Pull your DID programmatically: GET /api/business/{id}/.well-known/did.json with a Bearer token. Perfect for automation scripts.

One-command push

Run trustdid-setup --push and your did.json — along with its .vrfy signature and the .vrfy.log key-history chain — is uploaded to the server in one step. No manual uploads, no drift.

Deployment strategies

Choose the approach that fits your team and infrastructure. Ordered from simplest to most automated.

Manual download & deploy

Best for: individuals, small teams

The simplest approach. Download the ZIP from the dashboard, extract it to your web server root.

  1. Log into the TrustDID dashboard
  2. Click Download Bundle
  3. Extract the ZIP to your domain root (the .well-known/ directory is included)
  4. Check it: visit https://yourdomain.ca/.well-known/did.json

Frequency: whenever you rotate keys or add profiles. Typically a few times per year.

Scheduled pull script

Best for: small businesses, server admins

A cron job or Windows Task Scheduler that periodically pulls the latest DID from the TrustDID API and deploys it to your web root. Set it and forget it.

Linux / macOS (cron, daily at 3am)
# /etc/cron.d/trustdid-did-sync
0 3 * * * root curl -sS -H "Authorization: Bearer YOUR_TOKEN" \
  https://trustdid.ca/api/business/YOUR_ID/.well-known/did.json \
  -o /var/www/html/.well-known/did.json
Windows (PowerShell, scheduled task)
# sync-did.ps1
$headers = @{ "Authorization" = "Bearer YOUR_TOKEN" }
Invoke-WebRequest `
  -Uri "https://trustdid.ca/api/business/YOUR_ID/.well-known/did.json" `
  -Headers $headers `
  -OutFile "C:\inetpub\wwwroot\.well-known\did.json"
Using the TrustDID CLI
# Pull from API and auto-sign
trustdid-setup --pull
Tip: run trustdid-check after the pull to confirm everything is in sync. You can add it to the same cron job as a health probe.

Git-based workflow

Best for: dev teams, CI/CD environments

Store your did.json in a Git repository. Changes go through pull requests with review and approval. Merging to main triggers deployment via your existing CI/CD pipeline.

  1. Pull from API — a script fetches the latest DID from the dashboard into a branch
  2. Review the diff — the team sees exactly what changed (new key, rotated key, removed profile)
  3. Approve and merge — standard PR workflow with an audit trail
  4. CI/CD deploys — the pipeline copies .well-known/did.json to production
Example: GitHub Actions workflow
# .github/workflows/did-sync.yml
name: Sync DID Document
on:
  schedule:
    - cron: '0 3 * * *'  # daily
  workflow_dispatch:       # manual trigger

jobs:
  sync:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Pull latest DID
        run: |
          curl -sS -H "Authorization: Bearer ${{ secrets.TRUSTDID_TOKEN }}" \
            https://trustdid.ca/api/business/${{ secrets.TRUSTDID_ID }}/.well-known/did.json \
            -o .well-known/did.json
      - name: Create PR if changed
        uses: peter-evans/create-pull-request@v5
        with:
          title: "Update DID document"
          body: "Auto-synced from TrustDID dashboard"
          branch: did-update

This gives you Git history, diff review, approval gates, and automated deployment — the same workflow your team already uses for code.

Reverse proxy (transparent)

Best for: teams comfortable with web server config

Configure your web server to proxy /.well-known/did.json requests to the TrustDID API. Visitors hit your domain, but the response comes from TrustDID transparently. No manual deployment — changes appear instantly.

Nginx
location = /.well-known/did.json {
    proxy_pass https://trustdid.ca/api/business/YOUR_ID/.well-known/did.json;
    proxy_set_header Authorization "Bearer YOUR_TOKEN";
    proxy_cache_valid 200 5m;
}
Apache
<Location "/.well-known/did.json">
    ProxyPass "https://trustdid.ca/api/business/YOUR_ID/.well-known/did.json"
    RequestHeader set Authorization "Bearer YOUR_TOKEN"
</Location>
Trade-off: zero deployment friction, but it adds a runtime dependency on TrustDID API availability. If the API is down, your DID becomes unreachable. Consider a proxy_cache or a local fallback file as a safety net.

CLI push

Best for: automated environments, zero-delay deployment

The moment something changes, push it. One command uploads your did.json — together with its .vrfy signature and the .vrfy.log key-history chain — to the server. No polling, no waiting for a scheduled pull.

What gets pushed
# Push your identity files in one step
trustdid-setup --push

# Uploads:
#   did.json           — your DID document
#   did.json.vrfy      — its signature sidecar
#   did.json.vrfy.log  — the key-history audit chain

Run it by hand after a rotation, or wire it into the same script that rotates your keys — the push happens in seconds, fully automated. No cron jobs, no polling, no delay.

Because the .vrfy and .vrfy.log travel with the DID document, verifiers always see a key history that matches the keys you just published.

The key-history audit log

Rotations aren't just performed — they're recorded. Alongside the keyHistory inside your did.json, every rotation appends an entry to a tamper-evident, append-only sidecar log: did.json.vrfy.log.

Every rotation leaves a cryptographic trail
  • Dual-signed entries: each log entry is signed with both Ed25519 and ML-DSA-44 (post-quantum)
  • Hash-chained: every entry commits to the one before it — removing or rewriting history breaks the chain
  • Reason recorded: each rotation carries why it happened — scheduled-rotation, key-compromise, key-loss-recovery, policy-change, or initial-setup
  • Independently checkable: anyone can verify the whole chain — no account required
Rotating and verifying
# Rotate a key, recording why
trustdid-keytool --rotate PROFILE --rotation-reason key-compromise

# Verify the full key-history chain
trustdid-verify --verify-history

Old signatures keep verifying against the key that was active at signing time — the log is what lets a verifier prove which key that was, and that nobody quietly rewrote the past.

If you ever leave: the DID retirement policy

A signature is only as durable as the identity behind it. So we make this commitment publicly:

Your signatures verify forever — even if you leave.
  • Retired identities stay resolvable forever. Your DID document doesn't disappear.
  • Keep the domain alive — that part is yours. A did:web resolves through the domain it names, so an identity on your own domain outlives its keys only as long as the domain stays registered and serving. Budget for it the way you budget for archiving the documents themselves. (Hosted identities sit on our domain, which we keep.)
  • Signing stops; verification survives. When a license lapses, no new signatures can be made — but every document you signed keeps verifying.
  • Keys are deactivated, never deleted. They're marked deactivated in keyHistory, so verifiers can still resolve the key that was active when you signed.

Monitoring & health checks

Don't wait for a failed verification to discover your DID is out of date.

Run trustdid-check regularly
  • Local check: are your key files intact? Do .pub files match .pem files?
  • Remote check: does the published DID contain your key IDs?
  • Freshness check: does the dashboard copy match what's live on your domain?
  • Orphan detection: are there profiles on the server that aren't in your local config?

Add it to your cron job, CI/CD pipeline, or monitoring system. Exit code 0 = healthy, non-zero = action needed.

Quick smoke test
# Does my DID resolve?
curl -sS https://yourdomain.ca/.well-known/did.json | jq .id

# Does it match my local copy?
diff <(curl -sS https://yourdomain.ca/.well-known/did.json | jq -S .) \
     <(jq -S . ~/.trustdid/did.json)

Common pitfalls

Rotated keys, forgot to deploy
You ran --regenerate but didn't push the updated did.json to your website. Every verification now fails because the published key doesn't match.
Deployed the wrong file
Copied did.json to the wrong directory. It needs to be at exactly /.well-known/did.json — not /did.json or /.well-known/DID.json.
Stale cache
A CDN or browser is caching an old version. Set Cache-Control: max-age=300 (5 min) for /.well-known/did.json to balance freshness with performance.
Multiple machines, different keys
Two employees ran setup independently. Now two different key sets exist but only one is published. Use --deploy for new machines to add profiles to the existing org DID.

Publish once, then keep it in sync.

Still have questions? The FAQ covers key rotation, troubleshooting, enterprise deployment, and everything in between — read the FAQ.