The practices below are the difference between an identity system that survives production and one that becomes an incident report.

Key Hygiene

Do

Store private keys in HSM or OS keychain. Use platform-provided secure storage (Secure Enclave, StrongBox, TPM). Keys never exist in plaintext on disk.

Don't

Store keys in plaintext files or env vars. Plaintext key files can be read by any process; env vars appear in process listings and may be logged.

Do

Rotate keys every 90 days. Regular rotation limits the exposure window. Use the rotation flow to maintain identity continuity.

Don't

Use the same key pair indefinitely. Long-lived keys accumulate risk; if compromised, the attacker has the full identity history.

Do

Use separate keys for each purpose. Derive purpose-specific keys: authentication, assertion, delegation, and key agreement each get their own.

Don't

Reuse one key for signing, auth, and encryption. Key reuse violates least privilege — you cannot revoke one capability without revoking all.

Do

Zeroize key material immediately after use. Decrypted keys exist in memory only during signing; wrappers guarantee it even on panic.

Don't

Keep decrypted keys in memory across requests. Long-lived in-memory keys are vulnerable to memory dumps, core files, and cold boot attacks.
The key management guide covers the custody model this all rests on: one 32-byte seed, everything else derived.

Delegation Patterns

Do

Apply least privilege to delegations. Grant only the minimum permissions needed; use constraint fields to limit scope, duration, and resource access.

Don't

Delegate full capabilities when partial would suffice. If the delegatee is compromised, the attacker gains all parent capabilities.

Do

Set expiry times on all delegations. Short ops: 5–30 min TTL. Persistent agents: 24–72 hour windows with renewal.

Don't

Create delegations without expiry. Open-ended delegations cannot be cleaned up and persist if the parent loses the ability to revoke.

Do

Verify the no-amplification rule. A child must never exceed parent capabilities; every constraint is at least as restrictive as the parent’s.

Don't

Assume validation happens elsewhere. The rule must be enforced at creation time — downstream validation lets invalid delegations propagate.

Security Practices

Do

Verify lineage before trusting identity. Resolve, then verify the chain back to a human root — and for privileged paths, confirm the anchor’s answer too.

Don't

Trust a DID because it resolves. Resolution only proves existence. Without lineage verification (and an anchor for privileged paths), there is no human accountability — it could be an orphaned identity.

Do

Constant-time comparisons for all crypto values. Signatures, hashes, and key material must use constant-time functions.

Don't

Standard equality operators for crypto. They short-circuit on the first mismatch; attackers measure timing to learn matching bytes.

Do

Validate all inputs at the boundary. DIDs, JSON payloads, signatures, proofs: schema-validated before processing, malformed rejected immediately.

Don't

Parse and process without validation. Unvalidated inputs cause unexpected behavior or security vulnerabilities.

Do

Log verification audit trails. Record every decision with DID, timestamp, method, and result, in hash-chained (tamper-evident) logs.

Don't

Silently pass or fail verification. Without audit trails you cannot investigate incidents, prove compliance, or detect abuse patterns.

Error Handling

Do

Return specific error types per failure mode. Distinguish invalid DID, resolution failed, signature invalid, lineage broken, key expired, delegation revoked — each enables different recovery.

Don't

Generic error messages for all failures. A bare “verification failed” gives no information; callers cannot distinguish network from cryptographic errors.

Do

Handle network failures with fallback. Retry with exponential backoff, fall back to cache, use negative caching to prevent thundering herds.

Don't

Fail hard on the first network error. Transient failures are common; one timeout should not cascade into system-wide verification failure. (Authority paths are different: an unreachable anchor fails closed, because it cannot prove the negative.)

Do

Sanitize error messages before returning. Never include key material, internal paths, or stack traces in user-facing errors.

Don't

Include internal details in errors. Key IDs, endpoints, and debug info help attackers understand system internals.

The one-liner version

Persist the seed, derive everything else, verify before you trust, fail closed on authority, and log every decision you’ll need to defend later.

Next