DIDComm Messaging
DIDComm Messaging
DIDComm (DID Communication) is a secure, private messaging protocol built on top of Decentralized Identifiers. It’s the core protocol that enables Layr8’s peer-to-peer messaging capabilities.
What is DIDComm?
DIDComm is a messaging protocol that provides:
- Message-level security — each message is individually encrypted and signed
- Transport independence — works over any transport (HTTP, WebSocket, etc.)
- Asynchronous by design — no requirement for both parties to be online
- Privacy preserving — minimal metadata exposure
- Interoperable — standardized format works across implementations
Think of DIDComm as “email for machines” — but with built-in encryption, authentication, and privacy.
Core Concepts
Message Structure
Every DIDComm message has this basic structure:
{ "id": "1234567890", "type": "https://example.com/protocols/order/1.0/create", "from": "did:web:sender.com", "to": ["did:web:recipient.com"], "created_time": 1516269022, "body": { "order_id": "ORD-12345", "items": ["..."], "total": 150.00 }}Key fields:
- id — unique message identifier
- type — URI identifying the protocol and message type
- from / to — sender and recipient DIDs
- body — application-specific payload
Message Encryption
DIDComm uses Authenticated Encryption to ensure:
- Only intended recipients can read messages
- Recipients can verify the sender’s identity
- Messages can’t be tampered with
Plaintext Message → Encrypt with recipient's public key → Ciphertext ↓ Sign with sender's private keyMessages can be encrypted for multiple recipients — each receives their own encrypted copy using their public key from their DID Document.
Message Types
Messages are identified by type URIs that define the protocol, version, and message role:
https://didcomm.org/basicmessage/2.0/messagehttps://didcomm.org/trust-ping/2.0/pinghttps://example.com/supply-chain/1.0/shipment-updateThe type URI is the primary mechanism for routing messages to the correct handler. Agents register the types they support, and the node delivers matching messages.
DIDComm in Layr8
Transport Layers
Layr8 uses two transport layers:
- DIDComm transport (node-to-node) — gRPC and HTTPS carry encrypted DIDComm messages between nodes. These are the standard DIDComm transports, with WebSocket support coming soon.
- Plugin transport (agent-to-node) — WebSockets (Phoenix Channels) connect agents to their node. Agents send and receive messages over a persistent WebSocket connection.
Message Flow
1. Agent → Node (via WebSocket plugin connection) Agent creates a message and sends it to its node
2. Sender Node → Recipient Node (via gRPC / HTTPS) The node encrypts, resolves the recipient's DID, and routes the DIDComm message
3. Recipient Node → Agent (via WebSocket plugin connection) The recipient's node decrypts, verifies, and delivers to the connected agent
4. Agent processes the message Business logic handles the message and optionally sends a responseThe nodes handle all cryptographic operations — agents send and receive plaintext messages over their authenticated plugin connection.
Message Patterns
Fire and Forget
Send a message without expecting a response. Useful for notifications, status updates, and event streams. The message includes the recipient DID and a type, but no response is expected.
Request-Response
Send a message and wait for a reply. The response references the original message via thid (thread ID), allowing the sender to correlate request and response. Layr8 SDKs provide a request() method that handles this correlation automatically.
Threaded Conversations
Link related messages into a conversation thread:
{ "id": "msg-456", "type": "https://example.com/protocols/order/1.0/status_update", "thid": "msg-123", "pthid": "msg-001", "body": { "status": "shipped", "tracking": "UPS123456" }}- thid (thread ID) — links this message to an existing conversation thread
- pthid (parent thread ID) — links to a parent thread for nested conversations
Protocol Design
DIDComm protocols define the message types, sequencing rules, and roles for a particular interaction pattern.
Anatomy of a Protocol
A protocol defines:
- Protocol URI — unique identifier with version (e.g.,
https://example.com/protocols/procurement/1.0) - Roles — the participants (e.g., buyer, supplier)
- Message types — the messages exchanged, each suffixed to the protocol URI
- State machine — the valid message sequences
Example: Procurement Protocol
Protocol: https://example.com/protocols/procurement/1.0
Message types: /rfq_request Buyer → Supplier Request for quotation /rfq_response Supplier → Buyer Quotation with pricing /purchase_order Buyer → Supplier Formal order /order_confirmation Supplier → Buyer Order accepted /invoice Supplier → Buyer Payment request /payment_confirmation Buyer → Supplier Payment sentEach message type has an expected body structure. Both sides agree on the protocol — they can implement it independently using any language or SDK.
Protocol Versioning
Always version your protocols so implementations can evolve independently:
https://example.com/protocols/orders/1.0/...https://example.com/protocols/orders/1.1/...https://example.com/protocols/orders/2.0/...Minor versions (1.0 → 1.1) should be backward compatible. Major versions (1.x → 2.0) may introduce breaking changes.
Security Features
End-to-End Encryption
Every DIDComm message is encrypted specifically for its recipients using keys from their DID Documents. Messages can be addressed to multiple DIDs — each recipient receives their own encrypted envelope. Intermediaries (including Layr8 nodes) cannot read the message content.
Perfect Forward Secrecy
DIDComm supports ephemeral key exchange, meaning compromised long-term keys don’t expose past messages. Each conversation can use unique encryption keys derived from ephemeral key pairs.
Message Authentication
Every message includes cryptographic proof of the sender’s identity. Recipients verify the sender’s signature against the public key in their DID Document — no additional authentication step is needed.
Additional Message Features
Attachments
DIDComm messages can include attachments for files or large data:
{ "id": "msg-789", "type": "https://example.com/protocols/docs/1.0/share", "to": ["did:web:partner.com"], "body": { "description": "Q4 Financial Report" }, "attachments": [{ "id": "report-q4", "media_type": "application/pdf", "data": { "base64": "SGVsbG8gV29ybGQ=..." } }]}Message Expiry
Messages can include an expires_time field. Recipients should discard expired messages rather than processing them — useful for time-sensitive offers or temporary authorizations.
Best Practices
- Keep message bodies under 1MB — use attachments for large data, and consider chunking very large payloads
- Design for idempotency — messages may be delivered more than once; use the unique
idfield to detect and skip duplicates - Use problem reports for errors — DIDComm defines a standard problem report message type for communicating errors back to the sender
- Document your protocols — define message types, body schemas, and valid sequences so both sides can implement independently
Further Reading
- DIDComm Messaging Specification v2
- DIDComm Protocols
- JSON Web Encryption (JWE)
- JSON Web Signature (JWS)
Next Steps
- Getting Started — Build your first agent using DIDComm
- Example Agents — Working code demonstrating DIDComm patterns
- Verifiable Credentials — Decentralized trust built on DIDs