Message Token
This token represents a direct message sent from one profile to another.
A message token enables private, one-on-one communication between users. Unlike posts (which are broadcast to followers), messages are sent directly to a specific recipient and are not federated to other instances.
The token must contain an audience (aud) field pointing to the recipient of the message. For other constraints see the Action Tokens.
Content-Addressing
This token is content-addressed using SHA-256:
- The entire JWT token (header + payload + signature) is hashed
- Action ID format:
a1~{base64_hash} - See Content-Addressing & Merkle Trees for details
Attachments
The a (attachments) field can contain file references:
- Each entry is a file_id (
f1~...) - File IDs are content-addressed (SHA256 of file descriptor)
- Files contain multiple variants (different resolutions)
- See File Storage for details
Parent Reference
The optional p (parent) field enables message threading:
- Contains the parent message’s action_id (
a1~...) - Creates conversation threads and reply chains
- Parent must exist and be verified
Database Key
The database key for a message token is [iss, t, id]
Purpose: Each message has a unique ID, allowing multiple messages in a conversation thread. The key includes the action ID itself, so messages are never overridden.
Message Types
Simple Text Message
Basic text communication:
{
"iss": "alice.example.com",
"aud": "bob.example.com",
"iat": 1738483200,
"k": "20240101",
"t": "MSG",
"c": "Hey Bob, want to grab coffee tomorrow?"
}Message with Attachments
Messages can include files, images, or other attachments:
{
"iss": "alice.example.com",
"aud": "bob.example.com",
"iat": 1738483200,
"k": "20240101",
"t": "MSG",
"c": "Here's the photo from our trip!",
"a": ["f1~abc123..."]
}Reply to Message
Threading messages in a conversation:
{
"iss": "bob.example.com",
"aud": "alice.example.com",
"iat": 1738483210,
"k": "20240101",
"t": "MSG",
"p": "a1~xyz789...",
"c": "Sounds great! How about 10am?"
}Fields
| Field | Required | Description |
|---|---|---|
| iss | ✓ | The identity sending the message |
| aud | ✓ | The identity receiving the message |
| iat | ✓ | Timestamp when message was sent |
| k | ✓ | Key ID used to sign the token |
| t | ✓ | Token type (always “MSG”) |
| c | ✓ | Message content (markdown) |
| p | Parent message ID (for threading/replies) | |
| a | Attachments (files, images, etc.) | |
| exp | Optional expiration (for disappearing messages) |
Example
User @alice.example.com sends a message to @bob.example.com:
| Field | Value |
|---|---|
| iss | alice.example.com |
| aud | bob.example.com |
| iat | 2024-04-13T00:01:10.000Z |
| k | 20240101 |
| t | MSG |
| c | Hey Bob! Are you coming to the meetup tonight? |
Visibility and Federation
Message tokens are direct actions, meaning they are:
- Sent only to the specified audience (recipient)
- NOT broadcast to followers
- Private between sender and recipient
- Delivered to
POST https://cl-o.{recipient}/api/inbox
Federation Flow
When Alice sends a message to Bob:
- Alice’s instance creates a MSG token with
aud: bob.example.com - The token is signed by Alice’s private key
- The message is sent to
https://cl-o.bob.example.com/api/inbox - Bob’s instance verifies the signature
- Bob’s instance stores the message for Bob to read
- Bob receives a notification (via WebSocket bus or push notification)
Permission Checks
When receiving a message token:
- Verify signature: Ensure the token is signed by the claimed issuer
- Check audience: Verify
audfield matches the local user - Check relationship: Verify sender is connected or followed (configurable)
- Spam prevention: Check sender is not blocked
- Rate limiting: Enforce message rate limits per sender
Message Delivery
Messages use a different delivery mechanism than broadcast actions:
| Aspect | Broadcast Actions (POST) | Direct Messages (MSG) |
|---|---|---|
| Delivery | To all followers | To specific recipient only |
| Federation | Sent to multiple instances | Sent to one instance |
| Storage | Stored publicly (with permissions) | Stored privately |
| Visibility | Timeline/feed | Message inbox |
| Retry | Best-effort | Reliable delivery with retry |
Message Threading
Messages can be threaded using the parent (p) field:
Message 1 (no parent)
├─ Reply 1 (p: Message 1)
├─ Reply 2 (p: Message 1)
│ └─ Reply 3 (p: Reply 2)
└─ Reply 4 (p: Message 1)This allows for:
- Conversation continuity
- Quote/reply functionality
- Context preservation
Read Receipts
Read receipts can be implemented using ACK tokens:
{
"iss": "bob.example.com",
"aud": "alice.example.com",
"iat": 1738483220,
"k": "20240101",
"t": "ACK",
"p": "a1~xyz789...",
"c": "read"
}This acknowledges that Bob has read Alice’s message.
Encryption (Future)
While action tokens are already signed for authentication, end-to-end encryption of message content is a planned feature:
- Message content (
cfield) encrypted with recipient’s public key - Only sender and recipient can decrypt
- Server cannot read message content
- Forward secrecy with ephemeral keys
Message Storage
Messages are stored in MetaAdapter with:
- Sender and recipient identity tags
- Read/unread status
- Delivery status
- Optional expiration timestamp
Privacy considerations:
- Messages stored locally at sender and recipient instances
- Not replicated to other instances
- Can be deleted by either party
- Retention policies configurable per user
Notifications
New messages trigger notifications via:
- WebSocket Bus: Real-time notification if recipient is online
- Push Notifications: If configured and recipient is offline
- Email: Optional email notification for important messages
Notification payload includes:
- Sender identity
- Message preview (first ~100 characters)
- Timestamp
- Attachment indicator
Comparison with Conversations
| Feature | MSG (Message) | CONV (Conversation) |
|---|---|---|
| Participants | 1-to-1 | Group (multiple participants) |
| Status | ✅ Implemented | ⚠️ Future/Planned |
| Use Case | Direct messaging | Group chats |
| Audience | Single recipient | Multiple recipients |
See Also
- Action Tokens - Overview of all action token types
- Acknowledge Token - For read receipts
- Conversation Token - For group messaging (future)
- [Access Control](/architecture/data-layer/access-control/access - Permission checking for messages
- Federation - How messages federate between instances