The Session Initiation Protocol (SIP) "Join" Header
Extracted elements (30)
An explicit Join header is needed rather than addressing an INVITE to a conference URI because: the conference may not yet exist, the joining party may not know if the target dialog is part of a conference, and the joining party may not know the conference URI. This allows joining ordinary two-party calls.
For RFC 2543 compatibility, a to-tag or from-tag value of zero matches both a tag value of zero and a null tag, since RFC 2543 compliant UAs may omit tags.
The Join extension does not constitute wiretapping under RFC 2804 because one party is always aware of a Join request and can decline it. In many applications, additional elements of the RFC 2804 wiretap definition also do not apply (e.g., call centers where all parties know conversations are recorded).
Unlike 3rd-party call control (3pcc), the Join header enables distributed peer-to-peer call control without requiring a central point of control. This is preferable in many environments where centralized control is undesirable.
Unlike the Replaces header, the Join header has no limitation on use with early dialogs (not yet confirmed). This is an explicit design choice noted in the UAS behavior section.
Proxy servers require no new behavior to support this extension and simply pass the Join header transparently. However, a proxy may forward an INVITE with Join to an orthogonal set of Contacts (due to forking logic), in which case the request will fail.
The Join mechanism does not provide a way to match multiple dialogs, an entire call, an entire transaction, or to follow a chain of proxy forking logic — it matches exactly one dialog identified by call-id, to-tag, and from-tag.
A Join header MUST contain exactly one to-tag and exactly one from-tag, as they are required for unique dialog matching.
If a User Agent receives a 300-class response and acts on it by sending an INVITE to a Contact, the redirected INVITE MUST contain the same Join header that was present in the original request.
If both a Join header field and another header field with contradictory semantics (e.g., a Replaces header field) are present in a request, the request MUST be rejected with a 400 "Bad Request" response.
If more than one Join header field is present in an INVITE, or if a Join header field is present in a request other than INVITE, the UAS MUST reject the request with a 400 Bad Request response.
If no match is found but the Request-URI corresponds to a conference URI, the UAS MUST ignore the Join header and process the INVITE as if the Join header did not exist, allowing redirection to a conference URI.
If no matching dialog is found, the UAS rejects the INVITE with a 481 Call/Transaction Does Not Exist response. Likewise, if the Join header matches a dialog not created with an INVITE, the UAS MUST reject the request with a 481 response.
If the Join header field matches a dialog which has already terminated, the UA SHOULD decline the request with a 603 Declined response.
If the Join header field matches more than one dialog, the UA MUST act as if no match is found.
If the Join header matches an active dialog, the UA MUST verify that the initiator of the new INVITE is authorized to join the matched dialog, using standard SIP authentication mechanisms (Digest or S/MIME).
If the Referred-By header corresponds to the user being joined, the UA SHOULD treat the join as if authorized by the joined party. The Referred-By header MUST reference a corresponding, valid Referred-By Authenticated Identity Body.
If the UA cannot accept the new INVITE (e.g., cannot establish required QoS or keying, or has incompatible media), the UA MUST return an appropriate error response and MUST leave the matched dialog unchanged.
If the UAS is incapable of satisfying the Join request, it MUST return a 488 "Not Acceptable Here" response.
Invitations with the Join header MUST only be accepted if the peer requesting replacement has been properly authenticated using a standard SIP mechanism (Digest or S/MIME), and authorized to be joined with the target dialog.
UAs which support the Join header MUST include the "join" option tag in a Supported header field. UAs that want explicit failure notification if Join is not supported MAY include the "join" option in a Require header field.
Use of end-to-end security mechanisms to integrity protect and encrypt dialog information (Call-ID, to-tag, from-tag) used by the Join header is RECOMMENDED.
The Join header field is used to logically join an existing SIP dialog with a new SIP dialog. It contains the call-id, to-tag, and from-tag of the target dialog, and is only valid in INVITE requests. It enables features such as barge-in, message screening, and call center monitoring.
The "join" option tag is defined for use in Require and Supported headers. UAs supporting the Join header advertise this capability via Supported: join, and can require it via Require: join.
This document registers the "Join" SIP header field in the SIP header registry, defined in section 7.1, with no short form.
This document registers the "join" SIP option tag in the SIP option-tag registry, indicating support for the SIP Join header as defined in this document.
Authorization for joins is typically configured as local policy. Examples include UAs configured with a list of authorized identities (e.g., supervisors for call center agents) or transitive authorization assertions from a list of authorized certificate authorities.
The Join extension significantly changes SIP security: an eavesdropper who learns Call-ID, To, and From headers of a dialog could use the Join header to insert themselves into or monitor a conversation. Proper authentication (Digest or S/MIME) and authorization are therefore mandatory for accepting Join requests.
Upon receiving an INVITE with a Join header, the UAS transitions through: dialog matching (confirmed or early) → authorization check → resource allocation → accept (200 OK, begins mixing) or reject (400, 481, 486, 488, or 603). If the matched dialog is already terminated, the UAS SHOULD send 603 Declined.
The Join header ABNF is: Join = "Join" HCOLON callid *(SEMI join-param); join-param = to-tag / from-tag / generic-param; to-tag = "to-tag" EQUAL token; from-tag = "from-tag" EQUAL token. It must contain exactly one to-tag and one from-tag for unique dialog matching.