# WebSockets & Socket.io (/docs/websockets)



A socket needs a credential too. There are two ways to give it one.

## Recommended: a ticket from your server [#recommended-a-ticket-from-your-server]

Add an endpoint that returns a short-lived, single-use ticket for the socket. `api.getSocketToken(url)` calls it as a normal authenticated request (token attached, refreshed on 401) and returns only the ticket. The access token never leaves the worker.

```ts
import { io } from "socket.io-client";

const socket = io("https://realtime.example.com", {
  // A function, so every reconnect gets a fresh ticket.
  auth: async (cb) => cb({ token: await api.getSocketToken("/auth/socket-ticket") }),
});
```

A plain `WebSocket` can't set headers, so pass the ticket in the URL:

```ts
const ticket = await api.getSocketToken("/auth/socket-ticket");
const ws = new WebSocket(`wss://realtime.example.com/?ticket=${encodeURIComponent(ticket)}`);
```

The endpoint is called with `POST` (pass `{ method: "GET" }` to change that) and may return the ticket as a plain string or as `{ token }`, `{ ticket }` or `{ socketToken }`, optionally inside `{ data }`.

## Opt-in: the access token itself [#opt-in-the-access-token-itself]

If the socket server only accepts your API token, enable `exposeTokens`:

```ts
const api = createClient({ baseUrl, exposeTokens: true });

const socket = io(URL, {
  auth: async (cb) => cb({ token: await api.getAccessToken() }),
});
```

`getAccessToken()` refreshes first when the token is about to expire. The trade-off: any script on the page can now read the token. Use the ticket when you can.

## Reconnect when the session changes [#reconnect-when-the-session-changes]

```ts
api.onAuthStateChange((state) => {
  if (!state.isAuthenticated) socket.disconnect();
  else if (socket.connected) socket.disconnect().connect();   // fetches a new ticket
});
```
