Skip to content
Presence & ProtocolAn independent guide to Jabber and XMPP

Protocol

Presence, rosters and the subscription dance

Presence is not a status message. It is a routing decision the server makes on your behalf, from a list you own.

A hand ticking names on a printed contact list, several rows already marked, desk lamp lit.

Before anyone types a message, an XMPP account has announced one thing: that it is there. Presence looks trivial from outside and is quietly among the most closely governed parts of the protocol, built into the core specifications rather than added later by an extension. What follows is the machinery of RFC 6121: the roster the server keeps, the four subscription states, the handshake that produces them, and the probes that keep them honest.

Presence is an on/off signal

At its most basic, presence is a boolean: an entity is available or it is not. A client announces availability with a presence stanza that has no type attribute, and departure with one of type unavailable. The stanza carries no address; the server broadcasts it to every contact holding a subscription. That first announcement opens a presence session, closed later by unavailable presence, and for its duration the connected resource counts as an available resource. Presence is one of the three stanza kinds, and its plain form simply means availability.

Why does presence need permission?

Because it discloses something. To protect privacy, presence is revealed only to entities the user has approved, and that approval is called a subscription. It is not tied to a session: it lasts until the contact unsubscribes or the user cancels it. Four presence types manage the arrangement, subscribe, unsubscribe, subscribed and unsubscribed, and all of them travel between bare JIDs, the address without a device. Whenever a server sends one of the four outbound, it must stamp the sender’s bare JID rather than the full one, a rule the RFC says exists to prevent presence leaks. What goes into a JID therefore shapes every rule that follows.

A roster the server keeps for you

The contact list has a formal name, the roster, and its first surprise is custody: it is stored by the user’s server on the user’s behalf, so the same list reaches the account from any device. Clients manage it with iq stanzas carrying a query element in the jabber:iq:roster namespace. Each contact is an item with a required jid, an optional name the server treats as opaque, and any number of group buckets, which are not exclusive. Because a roster can hold confidential data, the server must restrict access to authorised entities, typically the account owner.

Four states in one attribute

Each item carries a subscription attribute with four values, named from the roster owner’s point of view, which is where most confusion begins.

The values of the subscription attribute
ValueMeaning
noneNeither side is subscribed to the other; the default
toThe user sees the contact’s presence, not the reverse
fromThe contact sees the user’s presence, not the reverse
bothEach side sees the other, the mutual subscription

A request in flight shows as none plus an ask attribute of subscribe, a sub-state the RFC calls “pending out”, and a pre-approved contact carries an approved flag that RFC 3921 never had. Clients may not write either flag; both change by sending presence. Every transition between the four states is catalogued in the text of RFC 6121.

How does a subscription begin?

With a presence stanza of type subscribe addressed to the contact’s bare JID, because the requester wants presence from all of the contact’s resources, not the one device named in a full address. The user’s server checks the syntax, trims a full JID back to its bare form if one slipped through, a check the RFC admits some implementations skip, then routes the stanza onward stamped with the sender’s bare JID.

The server then pushes a roster update to the user’s other devices: the contact, state none, ask set. That is what pending looks like on the wire. Should the contact stay silent, the server ought to resend the request after a configurable delay, because routing to a remote domain can fail silently.

What happens at the contact’s server?

The receiving server’s first duty is a prohibition. It must not approve a subscription on the contact’s behalf, unless that user was pre-approved, the account is configured to approve automatically, or an agreement allows it, an employment agreement being the RFC’s own example. A request needing a decision goes to the contact’s available resources; if none is online, the server stores the complete stanza and delivers it when one next appears, and again after that, until the contact decides, keeping only one request per user to blunt subscription request spam.

No roster item for the requester may exist before approval, and because stored stanzas invite resource exhaustion attacks, administrators are advised to cap how many requests the server will hold, and how large.

Approval, probes and ghosts

Approval is a single stanza of type subscribed, after which the two rosters mirror each other. The specification narrates the common case, bootstrapping a mutual subscription; the complete state machine sits in Appendix A. The payoff arrives at the next login, when initial presence is broadcast from the user’s full JID to every contact whose state is from or both, and to the user’s own other resources, an entity being implicitly subscribed to its own presence.

To gather what it missed, the server sends probes, presence of type probe from bare JID to bare JID. The replies read like a decision tree: unsubscribed if no subscription exists, unavailable if nothing is connected, otherwise the last presence from each available resource. RFC 3921 sent probes from full JIDs, and some implementations still do; the rule changed because subscriptions belong to the bare address. A server may also probe a quiet contact, which is how ghost contacts, online in appearance only, get cleared.

Watch the handshake from both sides

Two accounts of your own and one unanswered request show the whole machine at rest. Send a subscription request from one to the other and approve nothing. On the requesting side the contact appears at once, listed as none with ask set; on the receiving side nothing appears, since no item may exist before approval. Approve it and the rosters flip to to and from; repeat in the other direction and both settle on both.

rfc-editor.org

The IETF publishes its specifications as RFCs, and rfc-editor.org is where they are read. The page for RFC 6121, XMPP IM, is the 2011 revision of the messaging and presence specification first issued as RFC 3921 in 2004. Section 2 defines the roster, Section 3 the subscription flows, Section 4 the presence exchange, and Appendix A the full state machine behind this article.