Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Authentication

Two mechanisms, and they are not interchangeable.

auth — the Socket.IO handshake

socketOptions {
    auth {
        put("token", jwt)
        putJsonObject("meta") { put("deviceId", 42) }
    }
}

Sent as the CONNECT packet’s payload, per namespace. It is a JsonObject, so values can be strings, numbers, booleans or nested objects — not just strings.

Server-side this is socket.handshake.auth. Rejecting it there produces a SocketError.ConnectError carrying the server’s message and data, and moves the namespace to Failed.

This is the right place for a token in almost every case.

extraHeaders — HTTP headers

socketOptions {
    extraHeaders { put("Authorization", listOf("Bearer $jwt")) }
}

Applied to the HTTP polling requests and the WebSocket upgrade. Use these when a proxy or gateway in front of your server needs them, or when the server authenticates at the HTTP layer rather than in the Socket.IO handshake.

Note the value is a list — HTTP allows repeated headers.

On some platforms custom headers cannot be attached to a native WebSocket handshake. If you are websocket-only and headers seem to vanish, move the credential into auth, which travels in the Socket.IO payload and is unaffected.

Expiry and refresh

The library does not refresh tokens. There is no callback invoked on expiry and no retry with new credentials — options are an immutable snapshot taken at connect time.

When a token expires you get ConnectError and a Failed namespace. Recovery is yours:

socket.connectionState.collect { state ->
    if (state is ConnectionState.Failed && state.error is SocketError.ConnectError) {
        val fresh = refreshToken()
        client.close()
        client = SocketClient.connect(url, socketOptions { auth { put("token", fresh) } })
        client.namespace().openAwait()
    }
}

This is deliberate. A refresh hook would need to know your auth server, your retry policy and what counts as a permanent failure — all of which live in your app.