Skip to content

Client authentication and tokens ​

Pass an authentication token from the client, refresh it when it expires, and choose how it is sent with the WebSocket connection. The server counterpart is JWT authentication; the SDK works the same way with custom token schemes.

Provide the initial token ​

The simplest way is to include the token in the connection URL:

js
import { createCable } from '@anycable/web'

export default createCable(`ws://localhost:8080/cable?jid=${token}`)

Or pass it via the auth option:

js
export default createCable({
  auth: { token: 'secret-value' }
})

By default, the token is added as the jid query parameter, matching AnyCable JWT authentication. Use param to change the name:

js
export default createCable({
  auth: { token: 'secret-value', param: 'token' }
})

With @anycable/web, you can also inject the token into the page instead of into JS:

html
<meta name="cable-token" content="secret-token">
<!-- optionally, a custom param name -->
<meta name="cable-token-param" content="token">

Fetch the token before connecting ​

When the token can only be obtained via a request, you can still create the cable instance at application start and configure the transport lazily with transportConfigurator. It runs right before the connection is established:

js
import { createCable } from '@anycable/web'

export default createCable({
  transportConfigurator: async (transport, { initial }) => {
    // Only fetch on the first connection attempt
    if (!initial) return

    const response = await fetch('/token.json')
    const data = await response.json()

    transport.setToken(data.token, 'token')
  }
})

The configurator does not handle expiration; combine it with tokenRefresher below for long-lived clients.

Refresh expired tokens ​

The server checks the token only when a connection is established. The typical failure: a client reconnects after a network interruption, and its token has expired in the meantime. The server rejects it with the reason token_expired, and the SDK can then fetch a fresh token and reconnect on its own. Provide a tokenRefresher function:

js
// cable.js
import { createCable } from '@anycable/web'

export default createCable({
  tokenRefresher: async (transport) => {
    const response = await fetch('/token.json')
    const data = await response.json()

    // Update the whole URL...
    transport.setURL(`ws://example.com/cable?jid=${data.token}`)
    // ...or only the token
    transport.setToken(data.token)
  }
})

The refresher activates only on a token_expired disconnect ({"type":"disconnect","reason":"token_expired","reconnect":false}); network failures go through the regular reconnection flow.

For browser apps that embed the connection URL in HTML meta tags, there is a built-in refresher that reloads the current page in the background and reads the fresh URL and token from it:

js
import { createCable, fetchTokenFromHTML } from '@anycable/web'

export default createCable({ tokenRefresher: fetchTokenFromHTML() })

// or fetch a dedicated lightweight page
export default createCable({
  tokenRefresher: fetchTokenFromHTML({ url: '/custom-token-refresh-endpoint' })
})

Keep the refresh response small

fetchTokenFromHTML sends the X-ANYCABLE-OPERATION: token-refresh header with its request. Detect it on the backend and render only the meta tags instead of the full page.

Choose how the token is sent ​

Browsers cannot set custom headers on WebSocket connections, so query parameters are the default. In other environments you have more options, controlled by websocketAuthStrategy:

js
import WebSocket from 'ws'
import { createCable } from '@anycable/core'

const cable = createCable(url, {
  websocketImplementation: WebSocket,
  websocketAuthStrategy: 'header',
  auth: { token: 'secret-token' }
})
  • 'header' (Node.js, React Native): adds an x-<param>: <token> header to the connection request (x-jid with the default param name).
  • 'sub-protocol': appends an anycable-token.<token> entry to the WebSocket sub-protocols (the sec-websocket-protocol header). This works in browsers too and is supported by AnyCable server since v1.6.
  • Query parameter: the default, works everywhere.