Supporters
JOIN MY SPONSORS

Access Control

itty-sockets supports two types of keys that control who can do what on a channel.

Join Key

A join key is required to connect to a channel. Without the correct key, the connection is rejected with a 403.

join-key.js
// channel requires a join key
connect('myapp:private', {
  joinKey: 'correct-key',   // ✓ connected
})

connect('myapp:private', {
  joinKey: 'wrong-key',     // ✗ 403 rejected
})

connect('myapp:private')         // ✗ 403 rejected

Send Key

A send key controls who can send messages. Clients without the send key can still listen — they just can't broadcast.

send-key.js
// channel has a send key
const writer = connect('myapp:feed', {
  sendKey: 'write-pass',   // can send messages
})

const reader = connect('myapp:feed')  // can listen, can't send

writer.send('breaking news')    // ✓ sent
reader.send('hello')             // ✗ error, no send key

This is perfect for broadcast-style channels like live feeds, notifications, or dashboards where one source publishes and many clients listen.

Key Sources

Keys can come from two sources, with different behaviors:

Namespace Keys

Set via the Reservations dashboard. These apply to all channels under your namespace and can't be overridden by clients.

Ephemeral Keys (Open Channels)

On channels without a namespace reservation, the first client to connect can set their own keys:

ephemeral.js
// first joiner sets the rules
connect('my-room', {
  joinKey: 'secret',
  sendKey: 'writer-pass',
})

// now everyone else needs the joinKey
connect('my-room', { joinKey: 'secret' })  // ✓
connect('my-room')                         // ✗ rejected

These keys are ephemeral — they last only as long as the channel exists. When the last user disconnects, the channel is destroyed and the keys are gone.

Important: If a namespace reservation exists for a channel, ephemeral keys are blocked. The namespace owner's config always wins.

Config Priority

  1. Most specific namespace — e.g. myapp:private wins over myapp
  2. Parent namespace — default keys for all channels under the namespace
  3. Ephemeral (first joiner) — only for open channels with no namespace match
  4. None — fully open, anyone can join and send

Next: Recipes — common patterns and real-world examples.