Docs

Server auth

Mint scoped client tokens from your backend and publish without a WebSocket.

Your backend has two jobs: mint short-lived tokens so browsers never see your API key, and optionally publish or read data over REST.

Mint a token locally

createJwt signs a token in-process with no network call, which makes token endpoints fast and dependency-free:

import { createJwt } from '@foony/realtime';

export async function GET(request: Request) {
  const userId = await requireUser(request);
  const token = await createJwt(
    {
      clientId: userId,
      capability: { [`chat:${userId}:*`]: ['subscribe', 'publish', 'presence', 'history'] },
      ttlMs: 60 * 60 * 1000,
    },
    { key: process.env.FOONY_API_KEY! },
  );
  return new Response(token);
}

The browser side points an authCallback at this endpoint, see Auth and capabilities. On a Go backend, the Go SDK mints the same tokens with realtime.CreateJWT.

Mint a token via the service

If you prefer the service to sign, request one over REST. The response includes the expiry so you can cache until then:

import { Rest } from '@foony/realtime';

const rest = new Rest({ key: process.env.FOONY_API_KEY! });
const details = await rest.auth.requestToken({
  clientId: 'user-123',
  capability: { 'chat:*': ['subscribe', 'publish'] },
  ttl: 60 * 60 * 1000,
});

console.log(details.token, details.expires);

Without the SDK, the same operation is POST /keys/{keyName}/requestToken with Basic auth, documented in the REST API.

Publish from the server

The Rest client publishes, reads history, and snapshots presence over plain HTTPS, which suits serverless functions and cron jobs that should not hold a socket open:

const channel = rest.channels.get('announcements');
await channel.publish('deploy', { version: '2026.07.02' });

For a long-lived server process that also needs to receive messages, use the regular Realtime client with key auth instead.

Rules to remember

  • Token lifetime defaults to 1 hour and is capped at 24 hours.
  • The minted capability is the intersection of what you request and what the key holds.
  • clientId is required when minting: it is the identity presence and messages attribute to the user.