How-to

Use sessioned envelopes

Applies to: .NET SDK, Node.js SDK Last updated: 2026-06-11

Goal

Reduce per-message latency for an ongoing conversation by establishing a session up front. After the session is established, both sides cache the key locally; subsequent messages need no platform calls.

When to use sessions

Step 1 — Agree on a session ID

A session ID is any string both parties share. Typically the initiating party generates a UUID and sends it to the other party out of band (in an initial unsessioned message, in a JWT handshake, or via your application's own channel).

string sessionId = Guid.NewGuid().ToString();
// communicate sessionId to the other party

Step 2 — Each side pins the ASK once

Both sides fetch the shared key for this session and store it under the session ID:

// Sender side
string ask = await client.FetchAskAsync(recipientName);
client.PinAskForSession(sessionId, ask);

// Receiver side (in their process)
string ask = await client.FetchAskAsync(senderName);
client.PinAskForSession(sessionId, ask);

Step 3 — Send sessioned messages

string envelope = await client.EncryptEnvelopeAsync(
    recipient: recipientName,
    body:      "hello",
    sessionId: sessionId);

// The envelope is now in sessioned format (hsha:<hash>|<ciphertext>)
// and does NOT include the sender's source identifier on the wire.

Step 4 — Decrypt sessioned messages

Decrypt is identical to the unsessioned case — the SDK auto-detects the sessioned format and looks up the pinned ASK:

var msg = await client.DecryptEnvelopeAsync(envelope);
Console.WriteLine($"From {msg.Sender}: {msg.Body}");
Console.WriteLine($"FromSession: {msg.FromSession}"); // True

Session lifetime

A session lasts as long as the pinned ASK is in memory (or on disk if you have configured ASK persistence). The session is independent of the underlying transport — you can send messages months apart and the session still works, as long as both sides retain the pinned ASK.

See also