- Docs
- Core Concepts
- Authentication
- Token Auth
Token Auth
JWTs give clients temporary access without exposing the API key secret. Tokens are issued from an API key and can carry an alias and permission scope.
Use the API and Language controls to switch Socket vs REST and JavaScript vs React.
Using a token
Connect with a JWT via query/access_token, or let the SDK fetch one:
wss://socket.qpub.io/v1?access_token=<jwt>
import { QPub } from "@qpub/sdk";
const socket = new QPub.Socket({
authUrl: "https://your-app.example/api/qpub-token",
});
// Your authUrl should return { token: "<jwt>" }Call REST with a Bearer JWT:
curl -X POST "https://rest.qpub.io/v1/channel/demo/messages" \
-H "Authorization: Bearer <jwt>" \
-H "Content-Type: application/json" \
-d '{"messages":[{"data":{"text":"Hello"}}]}'
On a trusted server you usually keep using QPub.Rest({ apiKey }) instead of a JWT. For browsers, mint a JWT (or token request) on your backend and call REST with Authorization: Bearer <jwt> — or use Socket for realtime clients.
Issue a token (server)
Always mint tokens on a trusted server with the API key secret. This step is the same regardless of whether clients use Socket or REST.
REST endpoint
POST /v1/key/:keyID/token/issue
Authorization: Basic <base64(publicId:secret)>
:keyID is the API key public id.
Body (all optional):
{
"alias": "web-client-1",
"permission": {
"notifications": ["subscribe"],
"*": ["subscribe"]
},
"expiresIn": 3600
}
expiresIn is seconds (camelCase in the JSON body). Permission keys are channel resource names; see Permissions.
200 response:
{ "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..." }
SDK
import { QPub } from "@qpub/sdk";
const rest = new QPub.Rest({ apiKey: process.env.QPUB_API_KEY });
const token = await rest.auth.issueToken({
alias: "web-client-1",
permission: { notifications: ["subscribe"] },
expiresIn: 3600,
});
generateToken signs a JWT locally with the API key secret (convenient for trusted servers). Prefer issueToken when you want the platform to mint the token.
Token request
For untrusted clients, create a signed token request on your server, send it to the client, and let the client exchange it for a JWT. The secret never leaves your server.
Server
import { QPub } from "@qpub/sdk";
const rest = new QPub.Rest({ apiKey: process.env.QPUB_API_KEY });
const tokenRequest = await rest.auth.createTokenRequest({
alias: "Alice",
permission: { "chat.lobby": ["subscribe", "publish"] },
});
// Return tokenRequest to the client
Client
const socket = new QPub.Socket({
tokenRequest, // auto-requests a token on init when provided
});
// Or: await socket.auth.requestToken(tokenRequest);Exchange the token request for a JWT, then call REST with Bearer auth. Prefer Socket + tokenRequest for browser realtime clients.
import { QPub } from "@qpub/sdk";
const rest = new QPub.Rest();
const { token } = await rest.auth.requestToken(tokenRequest);
await fetch("https://rest.qpub.io/v1/channel/demo/messages", {
method: "POST",
headers: {
Authorization: `Bearer ${token}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
messages: [{ data: { text: "Hello" } }],
}),
});
REST exchange
POST /v1/key/:keyID/token/request
Content-Type: application/json
Body includes aki, timestamp, optional alias / permission, and signature (HMAC-SHA256 over a canonical string). Prefer the SDK helpers instead of signing by hand.
200 response (same shape as issue):
{ "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..." }
Auth events (SDK)
Listen on socket.auth:
token_updatedtoken_expiredtoken_errorauth_error
Auth lifecycle events (token_updated, token_expired, …) are exposed on the Socket client’s socket.auth. REST calls fail with HTTP errors when a JWT is missing or expired — refresh via your backend and retry.