Free 30-min Web3 Consultation
Book Consultation
Smart Contract Security Audits
View Audit Services
Custom DeFi Protocol Development
Explore DeFi
Full-Stack Web3 dApp Development
View App Services
Free 30-min Web3 Consultation
Book Consultation
Smart Contract Security Audits
View Audit Services
Custom DeFi Protocol Development
Explore DeFi
Full-Stack Web3 dApp Development
View App Services
Free 30-min Web3 Consultation
Book Consultation
Smart Contract Security Audits
View Audit Services
Custom DeFi Protocol Development
Explore DeFi
Full-Stack Web3 dApp Development
View App Services
Free 30-min Web3 Consultation
Book Consultation
Smart Contract Security Audits
View Audit Services
Custom DeFi Protocol Development
Explore DeFi
Full-Stack Web3 dApp Development
View App Services
LABS
Guides

Setting Up a Decentralized Identity-Based Messaging System

A developer tutorial for implementing a messaging protocol where user identities are rooted in DIDs and Verifiable Credentials, covering endpoint resolution, sender authentication, and social graph portability.
Chainscore © 2026
introduction
TUTORIAL

Setting Up a Decentralized Identity-Based Messaging System

A practical guide to building a private, user-controlled messaging application using Decentralized Identifiers (DIDs) and the W3C DIDComm protocol.

Decentralized Identity (DID)-based messaging shifts control from centralized servers to the user. Instead of accounts tied to a platform like WhatsApp or Telegram, users interact using portable Decentralized Identifiers (DIDs)—cryptographic identities they own. Messages are encrypted end-to-end using keys derived from these DIDs, ensuring only the intended recipient can read them. This tutorial uses the W3C DIDComm v2 protocol, the emerging standard for secure, interoperable communication between DIDs, to build a basic messaging flow.

The core components are a DID Document and a DID Method. A DID Document, hosted on a verifiable data registry like a blockchain or IPFS, contains public keys and service endpoints. For this example, we'll use the did:key method for simplicity, which generates a DID directly from a public key. First, generate a key pair and DID for two users, Alice and Bob. Here's how you might create a DID in TypeScript using the @digitalbazaar/did-method-key library:

typescript
import * as didKey from '@digitalbazaar/did-method-key';
const driver = didKey.driver();
const { didDocument, keyPairs } = await driver.generate();
// didDocument.id will be a DID like 'did:key:z6Mk...'

With DIDs created, Alice can discover Bob's DID Document to find his public keys and messaging endpoint. Using DIDComm, she creates an encrypted Message. This involves packing a plaintext JSON message into a JWM (JSON Web Message) encrypted specifically for Bob's public key. The didcomm npm package can handle this:

typescript
import { Message } from 'didcomm';
const message = new Message({
  id: '123',
  type: 'https://example.com/chat/1.0/message',
  body: { msg: 'Hello, Bob!' },
  to: [bobDid],
  from: aliceDid
});
const packedMessage = await message.pack_anoncrypt(bobPublicKey);

The resulting packedMessage is sent to Bob's service endpoint.

Bob receives the encrypted bundle and uses his private key to unpack and decrypt it. He then verifies the message's integrity and that it came from Alice's DID. This process ensures confidentiality, authenticity, and integrity without relying on a central message broker. The communication can occur over any transport layer (HTTP, WebSockets, Bluetooth) that can deliver the encrypted packet to the recipient's endpoint, making the system highly resilient.

For a production system, consider a more persistent DID method like did:ion (on Bitcoin) or did:ethr (on Ethereum), which allow for key rotation and service endpoint updates. You would also need to implement a mediator for offline messaging and handle more advanced DIDComm protocols for features like forward secrecy. The core principles, however, remain: user-owned identities, direct peer-to-peer encryption, and protocol-level interoperability, forming the foundation for a truly decentralized messaging future.

prerequisites
DECENTRALIZED MESSAGING

Prerequisites and Setup

This guide details the technical prerequisites for building a decentralized, identity-based messaging system using modern Web3 protocols. We'll cover the core components, required tools, and initial configuration.

A decentralized messaging system replaces centralized servers with a peer-to-peer network and cryptographic identities. The foundational prerequisites are a decentralized identity (DID) framework and a decentralized storage or transport layer. For identity, the W3C Decentralized Identifiers (DIDs) standard is essential, with implementations like did:key for simple keys or did:ethr for Ethereum-based identities. For the messaging layer, you'll need a protocol for peer discovery and encrypted message passing, such as libp2p or the Waku network (a fork of Whisper focused on scalability).

Your development environment must support these protocols. For a JavaScript/TypeScript stack, you'll need Node.js (v18+) and a package manager like npm or yarn. Core libraries include @veramo/core for DID and Verifiable Credential management, js-libp2p or js-waku for networking, and a cryptographic library like @noble/curves. If integrating with a blockchain for identity anchoring or incentivization, you'll also need an Ethereum provider such as Ethers.js v6 or Viem, and a testnet wallet (e.g., from Sepolia).

Start by initializing your project and installing the core dependencies. For a Veramo-based identity agent: npm init -y && npm install @veramo/core @veramo/did-manager @veramo/key-manager. Configure your agent to use a key management system (like @veramo/kms-local) and a DID provider (like @veramo/did-provider-key). This setup creates an agent object that can generate DIDs, manage keys, and create Verifiable Credentials, forming the identity core of your messaging application.

Next, set up the messaging transport. Using js-waku, install js-waku and create a Waku instance to connect to the test fleet. You must configure it to use protocols like Filter (for receiving messages) and Light Push (for sending messages). The Waku network uses content-based addressing, so messages are routed based on a contentTopic rather than a recipient's IP address. Your app will subscribe to topics relevant to your users' DIDs to receive their messages.

The final prerequisite is establishing the link between identity and messaging. A common pattern is to use a DID's public key to derive a static public key for an asymmetric encryption scheme, such as X25519 for ECDH key agreement. When User A wants to message User B, they encrypt the payload using a symmetric key derived from their private key and User B's public key. The encrypted message, along with the sender's DID, is then published to the recipient's content topic on the decentralized network.

With these components configured—a Veramo agent for identity, a Waku node for transport, and encryption logic linking the two—you have the foundation for a decentralized messaging system. The subsequent steps involve building the application logic for user discovery (e.g., via a DID resolver), managing conversation threads, and implementing a user interface. Remember to test thoroughly on testnets and the Waku test fleet before any production deployment.

architecture-overview
SYSTEM ARCHITECTURE OVERVIEW

Setting Up a Decentralized Identity-Based Messaging System

This guide outlines the core components and architecture for building a secure, user-owned messaging system using decentralized identifiers (DIDs) and verifiable credentials.

A decentralized identity-based messaging system shifts the paradigm from server-controlled accounts to user-owned identities. At its foundation are Decentralized Identifiers (DIDs), which are globally unique, cryptographically verifiable identifiers anchored on a blockchain or distributed ledger. Unlike an email address, a DID is not issued by a central provider; it is created and controlled by the user. This self-sovereign identity is the root for all interactions, enabling secure, private communication without relying on a central directory or service provider. The DID document, which contains public keys and service endpoints, is the primary mechanism for discovering how to communicate with an identity.

The architecture relies on three core protocols working in concert. First, the W3C DID specification provides the standard format for creating and resolving identifiers. Second, Verifiable Credentials (VCs) act as portable, tamper-proof attestations—like a cryptographic business card—that can be presented to establish trust. Third, a secure transport layer, often implemented using the Decentralized Web Node (DWN) specification or libp2p, handles the actual message routing and storage. Messages are encrypted end-to-end using keys derived from the participants' DID documents, ensuring that only the intended recipients can read them, even if the message is relayed through a public network of nodes.

For developers, implementing this starts with choosing a DID method, such as did:key for simplicity or did:ion for Bitcoin-based resilience. A typical stack includes a DID resolver library (e.g., did-resolver), a VC library (e.g., veramo or ssi-sdk), and a secure storage module for private keys. The backend service doesn't host user accounts; instead, it provides a relay or gateway that helps DWNs or peer-to-peer nodes find each other. User clients must securely manage their private keys, often using a wallet or agent, to sign and decrypt messages, making key management a critical part of the user experience.

A major advantage of this architecture is interoperability. Because it's built on open W3C standards, identities and credentials created in one system can, in principle, be used in another. This avoids platform lock-in. Furthermore, the system enhances privacy through selective disclosure; you can prove you are over 18 with a verifiable credential without revealing your birthdate or other identity details. The architecture also naturally supports offline-first messaging, as the DWN specification allows for messages to be stored and forwarded when a peer comes online, similar to how blockchain transactions are handled.

In practice, building this requires careful consideration of key recovery, incentive models for relay nodes, and spam prevention. However, the result is a messaging system aligned with Web3 principles: user sovereignty, censorship resistance, and verifiable trust. By leveraging DIDs as the foundational address book and VCs as the trust layer, developers can create communication protocols that are as open and resilient as the internet itself, returning control of data and relationships to the individual user.

key-concepts
DECENTRALIZED IDENTITY MESSAGING

Core Concepts

Build private, user-owned communication systems using decentralized identifiers (DIDs) and verifiable credentials.

06

Building a Basic Messaging Flow

  1. Connection: Two DIDs establish a peer-to-peer connection by exchanging DIDComm invitation and request messages.
  2. Authentication: Each party verifies the other's DID against their DID Document.
  3. Encryption: The sender uses the recipient's public key from their DID Doc to Authcrypt a message.
  4. Routing: The encrypted message is sent to the recipient's service endpoint declared in their DID Doc.
  5. Decryption & Response: The recipient decrypts the message with their private key and can reply, reusing the established secure channel.
step-1-did-creation
FOUNDATION

Step 1: Generating and Managing User DIDs

A Decentralized Identifier (DID) is the cryptographic anchor for your on-chain identity. This guide covers generating, storing, and resolving DIDs using the Ethereum Attestation Service (EAS) and the `did:ethr` method.

A Decentralized Identifier (DID) is a new type of globally unique identifier that an individual or entity controls directly, without reliance on a central registry. Unlike traditional usernames or email addresses, a DID is cryptographically verifiable. For Ethereum-based systems, the did:ethr method is a common standard, where a DID is derived directly from a user's Ethereum public key, formatted as did:ethr:<Ethereum-address>. This creates a self-sovereign identity foundation where the user's private key is the ultimate source of control.

To generate a DID, you first need an Ethereum account. In a frontend application, you can use libraries like ethers.js or viem to create a new wallet or connect an existing one via a provider like MetaMask. The DID is not minted on-chain; it is computed from the public key. For example, if a user's address is 0xAbC123..., their DID is automatically did:ethr:0xAbC123.... The critical step is key management: the private key must be secured, as it is the sole mechanism for creating verifiable proofs linked to this identity.

For persistent, verifiable identity data, we use attestations via the Ethereum Attestation Service (EAS). An attestation is a signed piece of data (a "claim") from one DID about another DID (or itself) that is recorded on-chain. For instance, a user (did:ethr:0xUser...) can create a self-attestation with a schema defining their public profile name and avatar URI. This on-chain record makes their identity details discoverable and trustable by others without relying on a central database.

Here is a conceptual code snippet for generating a DID and creating a self-attestation using EAS in a Node.js environment, assuming you have a signer object from an Ethereum wallet:

javascript
import { ethers } from 'ethers';
import { EAS, SchemaEncoder } from "@ethereum-attestation-service/eas-sdk";

// 1. Generate DID from wallet address
const signer = new ethers.Wallet(process.env.PRIVATE_KEY);
const userDID = `did:ethr:${signer.address}`;
console.log("User DID:", userDID);

// 2. Initialize EAS and create a profile attestation
const eas = new EAS("0x4200000000000000000000000000000000000021"); // Base Mainnet EAS
eas.connect(signer);

const schemaEncoder = new SchemaEncoder("string name,string avatar");
const encodedData = schemaEncoder.encodeData([
  { name: "name", value: "Alice", type: "string" },
  { name: "avatar", value: "ipfs://Qm...", type: "string" },
]);

const tx = await eas.attest({
  schema: "0x...", // Your registered schema UID
  data: {
    recipient: signer.address, // Self-attestation
    expirationTime: 0n, // No expiration
    revocable: true,
    data: encodedData,
  },
});

Managing DIDs involves resolving them to fetch their associated attestations and key rotation for security. A DID resolver fetches all on-chain attestations for a given DID, building a verifiable profile. If a private key is compromised, the did:ethr method allows for key rotation by deploying a smart contract (a DID registry) that updates the controlling key for an address, preserving the original DID string while shifting control—a significant advantage over static key pairs.

In summary, the workflow is: generate a DID from an Ethereum keypair, secure the private key, and use on-chain attestations (via EAS) to create a verifiable, portable identity dossier. This setup forms the bedrock for a decentralized messaging system, where every message can be signed by a DID and the sender's profile can be instantly resolved and trusted by the recipient.

step-2-endpoint-resolution
CORE PROTOCOL

Step 2: Resolving DIDs to Messaging Endpoints

Learn how to resolve a Decentralized Identifier (DID) to discover a user's messaging service endpoints, the essential step for initiating a secure, decentralized conversation.

A Decentralized Identifier (DID) is a portable, self-sovereign identifier, such as did:key:z6MkhaXgBZDvotDkL5257faiztiGiC2QtKLGpbnnEGta2doK. On its own, it's just a reference. To send a message, you must resolve this DID to a DID Document (DIDDoc). This document is a JSON-LD object that contains the cryptographic public keys for authentication and, crucially, the service endpoints where the user can receive messages. Resolution typically involves querying a decentralized network, like a blockchain or a peer-to-peer overlay, depending on the DID method (e.g., did:key, did:web, did:ion).

The DID Document's service array is where you locate messaging endpoints. For a system using the W3C DIDComm Messaging standard, you will look for a service entry with a type of DIDCommMessaging. This entry contains the serviceEndpoint property, which holds the URI where encrypted messages should be sent. This could be a traditional HTTPS URL, a WebSocket endpoint, or a URI for a peer-to-peer agent. Here is a simplified example of a relevant service entry in a DIDDoc:

json
{
  "id": "#didcomm-1",
  "type": "DIDCommMessaging",
  "serviceEndpoint": "https://agent.example.com/didcomm",
  "routingKeys": ["did:key:z6MkpTHR8VNsBxYAAWHut2Geadd9jSwuBV8xRoAnwWsdvktH"]
}

The routingKeys field is an advanced feature for mediators or relays. In a direct peer-to-peer model, your agent connects to the endpoint directly. However, if the recipient's agent is behind a firewall or not always online, they may use a mediator. The routingKeys list provides the DIDs of these forwarding agents. Your client must pack the message for the final recipient, then recursively forward-pack it for each routing key in order, ensuring only the intended final recipient can decrypt the core message. This enables reliable delivery without compromising privacy.

To perform resolution in code, you use a DID Resolver library. For instance, using the did-resolver library in JavaScript with the web and key method drivers, the process is straightforward. After resolving the DID, you parse the DID Document to find the correct service endpoint. This resolved endpoint is the final destination for your encrypted DIDComm message, completing the discovery phase of the communication protocol.

step-3-message-format
ARCHITECTURE

Step 3: Defining the Message Envelope Format

Design the standardized container that carries your decentralized identity messages across the network, ensuring interoperability and security.

The message envelope is the standardized data structure that wraps your actual message content. It serves as the universal package for all communication within your system, containing the necessary metadata for routing, verification, and processing. A well-defined envelope format ensures that messages from different senders can be understood by any compliant receiver, regardless of the underlying transport layer. Think of it as the digital equivalent of an addressed, stamped, and sealed letter, where the envelope's format is agreed upon by all postal services.

A robust envelope typically includes several key fields. The from and to fields contain the Decentralized Identifiers (DIDs) of the participants, acting as the immutable return and destination addresses. A type field specifies the message protocol (e.g., basicmessage, credential-offer), allowing the receiver to parse the inner body correctly. A unique id and timestamp are essential for preventing replay attacks and auditing. Finally, a proof field contains a cryptographic signature created by the sender's private key, which verifies the message's authenticity and integrity.

Here is a practical example of a JSON envelope for a simple text message using the DIDComm v2 standard as inspiration:

json
{
  "id": "123e4567-e89b-12d3-a456-426614174000",
  "type": "https://example.com/protocols/basicmessage/1.0/message",
  "from": "did:key:z6MkhaXgBZDvotDkL5257faiztiGiC2QtKLGpbnnEGta2doK",
  "to": ["did:key:z6MknGc3ocHs3zdPiJbnaaqDi58NGb4pk1Sp9WxWufuXSdxf"],
  "created_time": 1672531200,
  "body": {
    "content": "Your meeting is at 3 PM tomorrow."
  },
  "proof": {
    "type": "Ed25519Signature2020",
    "created": 1672531200,
    "verificationMethod": "did:key:z6MkhaXgBZDvotDkL5257faiztiGiC2QtKLGpbnnEGta2doK#z6MkhaXgBZDvotDkL5257faiztiGiC2QtKLGpbnnEGta2doK",
    "proofPurpose": "authentication",
    "proofValue": "z58DAdFfa9SkqZMVPxAQpic7ndSay..."
  }
}

The proof is the cornerstone of trust. When a message arrives, the receiver's agent must validate this signature. It fetches the sender's public key from their DID Document (resolved from the from field), and uses it to verify the proofValue. This process cryptographically confirms that the message was sent by the holder of the private key corresponding to that DID and that the content has not been tampered with in transit. Without a valid proof, the message should be rejected.

Your system's specification must document this envelope format exhaustively. Define all mandatory and optional fields, their data types, and their semantic meaning. Specify the supported signature suites (like Ed25519Signature2020 or JsonWebSignature2020) and the exact serialization method used for creating the signature (e.g., the JCS - JSON Canonicalization Scheme - for deterministic JSON). This clarity is what allows different developers to build interoperable agents that can seamlessly exchange messages.

step-4-relay-service
IMPLEMENTATION

Step 4: Building a Basic Message Relay

This guide walks through creating a functional message relay smart contract that enables users to send and receive encrypted messages using their decentralized identity (DID).

A message relay is a smart contract that acts as a public, permissionless mailbox. Users can submit encrypted messages intended for a specific recipient's DID, and the recipient can later retrieve them. The core logic involves two primary functions: sendMessage and getMyMessages. The contract does not handle encryption or decryption itself; it simply stores ciphertext on-chain, relying on the client-side wallet (like MetaMask with EIP-4361/ERC-55) to manage keys and encryption using the recipient's public key. This ensures end-to-end encryption where only the intended recipient can read the message.

Here is a basic Solidity implementation for a message relay contract. It uses a mapping to store an array of Message structs for each recipient address, which is derived from their DID. The sendMessage function accepts the recipient's address and the encrypted payload.

solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;

contract BasicMessageRelay {
    struct Message {
        address sender;
        string encryptedPayload;
        uint256 timestamp;
    }

    mapping(address => Message[]) private _userMessages;

    event MessageSent(address indexed sender, address indexed recipient);

    function sendMessage(address recipient, string calldata encryptedPayload) external {
        require(recipient != address(0), "Invalid recipient");
        require(bytes(encryptedPayload).length > 0, "Payload cannot be empty");

        _userMessages[recipient].push(Message({
            sender: msg.sender,
            encryptedPayload: encryptedPayload,
            timestamp: block.timestamp
        }));

        emit MessageSent(msg.sender, recipient);
    }

    function getMyMessages() external view returns (Message[] memory) {
        return _userMessages[msg.sender];
    }
}

To interact with this contract, a frontend dApp needs to perform several key steps. First, it must resolve a DID to an Ethereum address. For did:ethr or did:pkh methods, this often involves parsing the DID string. Next, before calling sendMessage, the dApp must encrypt the message content using the recipient's public key. Libraries like eth-sig-util or @metamask/eth-sig-util can be used for asymmetric encryption. The resulting ciphertext (often a hex string) is then sent as the encryptedPayload parameter. The emitted MessageSent event allows for efficient off-chain indexing by services like The Graph.

This basic design has important limitations. Storing data on-chain is expensive, and string data is particularly costly. For production systems, consider using layer 2 solutions like Arbitrum or Optimism to reduce gas fees, or an off-chain storage pattern with on-chain pointers (e.g., storing a content hash on-chain and the full ciphertext on IPFS or a decentralized storage network like Ceramic). Furthermore, the current contract lacks features like message status (read/unread) or the ability for senders to retract messages, which would require more complex state management.

To deploy and test, use a development framework like Hardhat or Foundry. After deploying to a testnet (e.g., Sepolia), you can write scripts to simulate sending a message. A critical integration test is to ensure the encryption flow works end-to-end: generate a test message, encrypt it for a recipient's public key, send it via the contract, retrieve it, and successfully decrypt it using the recipient's private key. This verifies the separation of concerns between the on-chain relay and off-chain cryptography.

The next step after a working relay is to enhance the user experience and system robustness. This includes adding push notifications via services like EPNS or XMTP, implementing meta-transactions for gasless sends, or creating a schema system for different message types (e.g., text, transaction requests). The foundational pattern demonstrated here—on-chain mailbox, off-chain encryption—is a core building block for decentralized communication systems built on DIDs and blockchain identity.

step-5-social-graph
DECENTRALIZED MESSAGING

Step 5: Creating a Portable Social Graph with VCs

Build a messaging system where user identity and social connections are controlled by the user, not a central server, using Verifiable Credentials (VCs).

A decentralized identity-based messaging system shifts the core data model from a centralized database to a user-owned, portable social graph. Instead of storing friend lists and profiles on a company's server, this data is expressed as Verifiable Credentials (VCs). A user can hold a VC from a contact that states, "Alice attests to knowing Bob." This credential is a cryptographically signed piece of data stored in the user's own digital wallet, such as a W3C Decentralized Identifier (DID). The messaging application queries the user's wallet for these connection VCs to build the contact list interface.

The protocol flow for sending a message involves three core steps: authentication, discovery, and delivery. First, the sender authenticates using their DID. To find the recipient's messaging endpoint, the sender resolves the recipient's DID Document, which should contain a service endpoint for messages (e.g., "type": "DIDCommMessaging"). Finally, the message itself is encrypted using the recipient's public key (found in their DID Document) and sent to their endpoint. This ensures that only the intended recipient, who holds the corresponding private key, can decrypt it, providing strong end-to-end encryption by design.

Implementing this requires specific libraries and standards. For creating and verifying VCs, use the W3C Verifiable Credentials Data Model with libraries like did-jwt-vc or vc-js. For DID management and resolution, tools like did-resolver and universal resolver drivers are essential. The actual message transport often uses the DIDComm v2 protocol, which standardizes how DIDs are used for secure, peer-to-peer communication. A basic message payload is a signed JWM (JSON Web Message) encrypted with JWE (JSON Web Encryption).

Here is a simplified code example for creating a connection credential and a DIDComm message using hypothetical libraries:

javascript
// 1. Create a 'Connection' Verifiable Credential
const connectionVC = await vc.issue({ // vc is an instance of a VC library
  issuer: aliceDID, // DID of the person giving the credential
  subject: bobDID,   // DID of the person being connected to
  credential: {
    '@context': ['https://www.w3.org/2018/credentials/v1'],
    type: ['VerifiableCredential', 'ConnectionCredential'],
    credentialSubject: { id: bobDID, relationship: 'knows' }
  }
});
// Bob stores `connectionVC` in his wallet.

// 2. Create a DIDComm encrypted message
const message = {
  type: 'https://didcomm.org/basicmessage/2.0/message',
  body: { content: 'Hello, Bob!' }
};
const encryptedMessage = await didcomm.packEncrypted({
  message: message,
  to: bobDID, // Recipient's DID
  from: aliceDID // Sender's DID
});
// Send `encryptedMessage` to Bob's service endpoint

This architecture has significant advantages. It creates user sovereignty: relationships are portable and can be used across different messaging apps that support the same standards. It enhances privacy and security by minimizing data stored on central servers and using strong cryptography. It also enables interoperability, as different applications can read the same social graph VCs. However, challenges remain, such as ensuring the availability of message endpoints (solving for "DID resolution to an online inbox") and managing the user experience of handling cryptographic keys.

To move forward, developers should explore implementations like DIDComm v2 for the messaging layer and Cheqd's AnonCreds or Spruce ID's kits for credential management. The Decentralized Identity Foundation (DIF) and W3C Credentials Community Group are key forums for specifications. The goal is to build messaging where the network is the protocol, not the platform, returning control of social data to the individual user.

PROTOCOL SELECTION

DID Method Comparison for Messaging

Key technical and operational differences between popular DID methods for building decentralized messaging systems.

Featuredid:keydid:ethr (Ethereum)did:web

Key Management

Local generation only

On-chain public key, local private

Web server TLS certificate

Decentralization Level

Peer-to-peer

Ethereum blockchain

Centralized web domain

Resolver Latency

< 100 ms

2-15 sec (depends on RPC)

< 500 ms

Update/Revoke Capability

None (static)

Yes, via smart contract

Yes, via server control

Message Encryption Support

Yes (X25519)

Yes (X25519, Secp256k1)

Yes (depends on implementation)

Typical Use Case

Ephemeral sessions, demo apps

Web3 wallets, on-chain identity

Enterprise pilots, controlled env.

DID Document Size

~500 bytes

~1.5 KB (with VC)

Varies, often >2 KB

Primary Development SDK

@digitalbazaar/did-method-key

ethr-did-resolver, Veramo

did-resolver, custom HTTP client

DEVELOPER FAQ

Frequently Asked Questions

Common technical questions and solutions for building decentralized identity-based messaging systems using protocols like XMTP, WalletConnect, and ENS.

A Decentralized Identifier (DID) is a cryptographically verifiable identifier that you own and control, independent of any centralized registry. For messaging, DIDs replace traditional usernames or email addresses. A user's DID is typically derived from their blockchain wallet address (e.g., did:pkh:eip155:1:0xabc...).

How it works:

  1. A user's DID is resolved to a DID Document containing public keys and service endpoints.
  2. Messaging protocols like XMTP use this document to find the user's messaging inbox network address.
  3. End-to-end encrypted sessions are established using the keys in the DID Document, ensuring only the intended recipient can decrypt messages.

This architecture enables permissionless, secure, and interoperable messaging without relying on a central server to manage identities.