Subscription Token

This token represents a subscription to a subscribable action, such as a conversation (CONV). Subscriptions control who receives messages and updates from group activities.

The subscription token must contain both a subject (sub) field referencing the subscribable action and an audience (aud) field specifying the owner of that action. 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}
  • Changing any field invalidates the action_id
  • See Content-Addressing & Merkle Trees for details

Immutability: Once created, a SUBS token cannot be modified without changing its action ID.

Purpose

SUBS tokens serve several important purposes:

  1. Membership Management: Track who is part of a conversation or group
  2. Message Delivery: Determine who receives messages sent to the group
  3. Role Assignment: Assign permissions (observer, member, moderator, admin)
  4. Participation Control: Enable joining, leaving, and role changes

Required Fields

Field Required Description
iss Yes The subscriber’s identity
aud Yes The owner of the subject action (e.g., CONV creator)
sub Yes The action_id being subscribed to (a1~...)
t Yes “SUBS”, “SUBS:UPD”, or “SUBS:DEL”
c Optional Subscription metadata (role, invitedBy, message)

Subtypes

Subtype Description
SUBS Create a new subscription (join)
SUBS:UPD Update subscription (change role)
SUBS:DEL Delete subscription (leave)

Content Structure

The optional content (c) field contains subscription metadata:

{
  "role": "member",
  "invitedBy": "alice.cloudillo.net",
  "message": "Joining the team discussion"
}
Property Type Required Description
role string No Participant role: “observer”, “member”, “moderator”, “admin”
invitedBy string No Identity of the user who invited this subscriber
message string No Optional message when joining

Database Key

The database key for a subscription token is {type}:{sub}:{iss}

This ensures only one active subscription per user per subject. Example: SUBS:a1~conv123:alice.example.com.

Auto-Accept Logic

When a SUBS token is received, the system determines whether to accept it automatically:

Subscription received
         β”‚
         β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ Check auto-accept conditionsβ”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
            β”‚
    β”Œβ”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
    β–Ό               β–Ό               β–Ό               β–Ό
Subject has    INVT exists     Issuer is      Otherwise
'O' flag?      for user?       subject creator?
    β”‚               β”‚               β”‚               β”‚
    β–Ό               β–Ό               β–Ό               β–Ό
 Accept          Accept          Accept          Reject
 (Open)         (Invited)       (Creator)      (status='R')

If none of the conditions shown in the diagram are met, the subscription is rejected (status=‘R’).

Participant Roles

Each role is a superset of the one below it. Default role is member.

Role Additional permissions
observer Read only
member + write (send messages)
moderator + invite/remove members
admin + manage conversation settings

Federation Flow

Subscribing to a Conversation

User creates SUBS token
         β”‚
         β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ Local processing            β”‚
β”‚ - Validate subject exists   β”‚
β”‚ - Check for INVT or 'O'     β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
            β”‚
            β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ schedule_delivery()         β”‚
β”‚ - Send to subject owner     β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
            β”‚
            β–Ό
    Owner receives SUBS
         β”‚
         β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ on_receive hook             β”‚
β”‚ - Check auto-accept logic   β”‚
β”‚ - Accept or reject          β”‚
β”‚ - Update subscription list  β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Message Fan-Out and Leaving

Once subscribed, messages are delivered via schedule_subscriber_fanout() which walks the parent chain to the CONV and delivers to all subscribers. See Subscriber Fan-Out for details.

To leave, the user creates a SUBS:DEL token. The subject owner marks the subscription as deleted and removes the user from the subscriber list.

Example

User @bob.cloudillo.net subscribes to a conversation owned by @alice.cloudillo.net:

Field Value
iss bob.cloudillo.net
aud alice.cloudillo.net
iat 2024-04-13T00:01:10.000Z
k 20240301
t SUBS
sub a1~NAado5PS4j5+abYtRpBELU0e5OQ+zGf/tuuWvUwQ6PA=
c {“role”: “member”, “invitedBy”: “alice.cloudillo.net”}

Status Values

Status Description
A (Active) Subscription is active, user receives messages
R (Rejected) Subscription was rejected (no invitation, not open)
D (Deleted) User left or was removed from the group

See Also