Tokens
Centrifugo authenticates a connection with a JWT and a private channel with a subscription JWT. Your backend signs them; the plugin passes them on and asks the frontend for new ones when needed.
Connection token
Two ways to give the first token:
token: "<jwt>" | requestToken: true | |
|---|---|---|
| First connect | Uses token at once. | Emits need_token and waits for provideToken. |
| Before the token expires | Emits need_token. | Emits need_token. |
| Neither set | Anonymous connection, need_token never comes. | — |
The need_token handler is installed only when token is set or requestToken: true, so
anonymous connections never wait for the frontend.
import { connect, onNeedToken, provideToken } from "tauri-plugin-centrifugo-api";
await onNeedToken(async () => {
try {
const token = await fetch("/api/centrifugo/token").then((r) => r.text());
await provideToken(token);
} catch {
await provideToken(""); // see below
}
});
await connect({ url, channels: [], useProtobuf: false, requestToken: true });
Register the listener before connect(). There is no timeout: the SDK waits for the answer as
centrifuge-js does, and disconnect() ends the wait. A newer request replaces an older unanswered
one; the old one is retried, not treated as unauthorized.
What to answer
| Call | Effect |
|---|---|
provideToken(token) | Answers the pending need_token. Rejects when none is pending. |
provideToken("") | "No token": an anonymous connect on the first connect; on a refresh the server disconnects the client as unauthorized (disconnected, code 1). |
refresh({ token }) | Answers the pending need_token; when none is pending, sets the token for the next connect. |
setToken(token) | Replaces the token used from the next connect attempt; does not answer a request. |
All of them reject with NotConnected when there is no client (provideToken with "no token
request in progress").
Subscription tokens
A subscription created with token refreshes it the same way, per channel:
import { addSubscriptionWithOptions, onNeedSubToken, subRefresh } from "tauri-plugin-centrifugo-api";
await onNeedSubToken(async ({ payload }) => {
const token = await fetch(`/api/centrifugo/sub-token?channel=${encodeURIComponent(payload.channel)}`)
.then((r) => r.text());
await subRefresh({ channel: payload.channel, token });
});
await addSubscriptionWithOptions({ channel: "$private:42", token: firstToken });
need_sub_token carries channel and ts. subRefresh rejects when no request is pending for
that channel. An empty token means unauthorized: the subscription ends with unsubscribed.
Subscriptions without token (including those from channels) never ask; channels that need a
token must be added with addSubscriptionWithOptions.
Expiry and refresh
The SDK reads the ttl the server returns for the token and asks for a new one shortly before
it expires; there is nothing to schedule in the app. If the token has already expired on
connect, the server answers with "token expired" and the SDK asks again.
Signing tokens is your backend's job, for example with the HMAC secret
(token_hmac_secret_key in Centrifugo v5) and the sub claim for the user ID; for subscription
tokens also channel.