Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/strophe/strophejs/llms.txt

Use this file to discover all available pages before exploring further.

Strophe.js provides two mechanisms that allow a BOSH client to resume an authenticated session without going through the full SASL login flow again: prebind with attach() and keepalive with restore(). Both mechanisms are BOSH-only features — they rely on the rid/sid token pair that BOSH sessions carry, which has no equivalent in the WebSocket transport.

Comparison at a Glance

attach() — Prebind

A server process authenticates on behalf of the user and passes the resulting jid, sid, and rid to the browser. The browser calls attach() to claim the pre-authenticated session. No password is ever exposed to the client.

restore() — Keepalive

Strophe.js caches jid, sid, and rid in sessionStorage while the page is open. On the next page load the browser calls restore() to resume the same BOSH session — no re-authentication needed unless the session expired.

Prebind / attach()

Prebinding is a pattern where a trusted server-side process opens a BOSH session, authenticates the user, and then hands the session tokens to the browser. This keeps the user’s credentials entirely server-side and eliminates the client-side login round-trip.

Server-Side Flow

The server must:
  1. Open a BOSH session with the XMPP server (POST to /http-bind)
  2. Complete SASL authentication and resource binding on behalf of the user
  3. Return the final jid, sid, and rid to the browser
A minimal Python example using the BOSHClient from the Strophe.js repository:
from attach.boshclient import BOSHClient

def prebind_view(request):
    bc = BOSHClient(
        jabberid='user@example.com',
        password='secret',
        bosh_service='http://xmpp.example.com:5280/http-bind'
    )
    bc.startSessionAndAuth()

    # Return tokens to the browser (e.g. as JSON or embedded in HTML)
    return {
        'jid': str(bc.jabberid),
        'sid': bc.sid,
        'rid': bc.rid,
    }

connection.attach() Parameters

connection.attach(
  jid: string,       // Full JID bound by the session, e.g. 'user@example.com/res'
  sid: string,       // BOSH Session ID returned by the server
  rid: number,       // Next valid Request ID (typically server's last rid + 1)
  callback: Function,// Connect callback (same signature as connection.connect callback)
  wait?: number,     // HTTPBIND wait value (default: 60)
  hold?: number,     // HTTPBIND hold value (default: 1)
  wind?: number      // HTTPBIND window value (default: 5)
)
The rid passed to attach() must be exactly one greater than the last rid used by the server-side process. If you pass the same rid that the server last sent, requests will fail. The Python BOSHClient example above leaves bc.rid at the last sent value; increment it by 1 before passing it to attach().

Prebind Example

1

Server authenticates and returns tokens

Your backend authenticates the user over BOSH and returns the session tokens to the page — for example, as JSON in an API response or embedded in the HTML template.
<!-- Tokens embedded in HTML by the server -->
<script>
  window.PREBIND = {
    jid: 'alice@example.com/web',
    sid: 'a1b2c3d4e5f6',
    rid: 1048576,
  };
</script>
2

Create a BOSH Connection

Point Strophe.js at the same BOSH endpoint the server used.
import { Strophe } from 'strophejs';

const connection = new Strophe.Connection('https://xmpp.example.com/http-bind');
3

Call attach() instead of connect()

Pass the server-provided jid, sid, and rid directly. Do not call connect().
const { jid, sid, rid } = window.PREBIND;

connection.attach(jid, sid, rid, (status, condition) => {
  if (status === Strophe.Status.ATTACHED) {
    console.log('Session attached for', connection.jid);
    // Register handlers and start using the connection
  } else if (status === Strophe.Status.ATTACHFAIL) {
    console.error('Attach failed:', condition);
    // Fall back to a normal login
  } else if (status === Strophe.Status.DISCONNECTED) {
    console.log('Disconnected.');
  }
});
4

Handle ATTACHFAIL gracefully

If the BOSH session has expired or the tokens are wrong, the connection callback receives ATTACHFAIL. Always fall back to a normal connect() in this case.
function onConnect(status: number, condition?: string | null) {
  if (status === Strophe.Status.ATTACHFAIL) {
    console.warn('Prebind expired, falling back to full login');
    connection.connect('alice@example.com', 'password', onConnect);
  }
}

ATTACHED vs CONNECTED

StatusMeaning
Strophe.Status.CONNECTEDFull login completed; SASL authentication and resource binding finished by Strophe.js
Strophe.Status.ATTACHEDStrophe.js has claimed an externally pre-authenticated BOSH session; no re-authentication performed
Both statuses indicate that the connection is ready and stanza handlers can be registered. Your callback code should handle both.

Keepalive / restore()

When keepalive: true is set, Strophe.js writes the current jid, rid, and sid to sessionStorage['strophe-bosh-session'] as JSON after every successful BOSH request. When the page reloads, calling restore() reads those tokens back and calls _attach() internally — producing an ATTACHED status if the session is still valid.

ConnectionOptions.keepalive

const connection = new Strophe.Connection('/http-bind/', { keepalive: true });
Keepalive tokens are written automatically as long as the connection is authenticated. They are removed on logout by _doDisconnect().

connection.restore() Parameters

connection.restore(
  jid?: string,       // Optional: verify the cached session belongs to this bare JID
  callback: Function, // Connect callback
  wait?: number,      // HTTPBIND wait value
  hold?: number,      // HTTPBIND hold value
  wind?: number       // HTTPBIND window value
)
If jid is provided, restore() compares it against the cached jid (using bare JID comparison) and throws StropheSessionError if they do not match. Pass undefined to restore any cached session. restore() throws StropheSessionError (not a regular Error) when:
  • sessionStorage is unavailable
  • No cached session exists
  • The transport is not BOSH

Keepalive + Restore Example

import { Strophe } from 'strophejs';

const connection = new Strophe.Connection('/http-bind/', { keepalive: true });

function onConnect(status: number, condition?: string | null) {
  if (status === Strophe.Status.CONNECTED) {
    console.log('Logged in as', connection.jid);
  } else if (status === Strophe.Status.ATTACHED) {
    console.log('Session restored for', connection.jid);
  } else if (status === Strophe.Status.CONNFAIL) {
    console.error('Failed:', condition);
  } else if (status === Strophe.Status.DISCONNECTED) {
    console.log('Disconnected.');
  }
}

// Try to restore a session from sessionStorage.
// If no session is cached, fall back to a full login.
try {
  connection.restore(undefined, onConnect);
} catch (e) {
  if ((e as Error).name === 'StropheSessionError') {
    // No cached session — authenticate normally
    connection.connect('alice@example.com', 'password', onConnect);
  } else {
    throw e;
  }
}

Pausing and Resuming Request Processing

connection.pause() and connection.resume() let you temporarily suspend all outgoing data without disconnecting. This is useful when you need to batch many send() calls together — particularly over BOSH, where batching reduces the number of HTTP round-trips.
// Pause to batch several stanzas
connection.pause();

connection.send(presenceStanza);
connection.send(iqStanza);
connection.send(messageStanza);

// Resume — all three stanzas are dispatched in the next idle cycle
connection.resume();
When connection.paused is true, both the Bosh._onIdle() and Websocket._onIdle() handlers skip sending any queued data. Calling resume() sets paused back to false, and the next idle cycle (every 100 ms) dispatches all queued stanzas.

Transport Compatibility Note

attach() (BOSH form), restore(), and keepalive are BOSH-only features. Calling restore() with a WebSocket connection (ws:// or wss://) throws a StropheSessionError immediately. For WebSocket connections, use the normal connect() flow every time.pause() and resume() work with both BOSH and WebSocket transports — both transports check connection.paused in their idle handlers and stop sending while it is true.

Build docs developers (and LLMs) love