Skip to Content
Auth-Aware Client

Auth-Aware Client

If your service uses expiring tokens or loads user context separately from raw auth, your Kalam client should follow the same lifecycle: build once, refresh credentials when auth changes, and start subscriptions only when the session is ready.

This avoids a common failure mode — opening live subscriptions before you know which user or tenant the worker operates as.

  1. Build a shared KalamLinkClient (or Arc<KalamLinkClient>) at service startup.
  2. Resolve auth with AuthProvider::jwt_token(...) or a DynamicAuthProvider.
  3. Call connect() before live work when you want the WebSocket warm.
  4. Start live() or consumer() loops only after credentials and namespace context are known.
  5. Call disconnect(), close subscriptions/consumers, and drop the client on shutdown.

See also Authentication, Realtime Subscriptions, and Client Lifecycle.

Dynamic auth provider

Use DynamicAuthProvider when credentials must be fetched lazily on every connect or reconnect — OAuth/OIDC flows, secret managers, or rotating refresh tokens.

RUST
use std::{future::Future, pin::Pin, sync::Arc}; use kalam_client::{AuthProvider, DynamicAuthProvider, KalamLinkClient, Result}; struct TokenStore {    // e.g. Arc<RwLock<Option<String>>>} impl DynamicAuthProvider for TokenStore {    fn get_auth(        &self,    ) -> Pin<Box<dyn Future<Output = Result<AuthProvider>> + Send + '_>> {        Box::pin(async move {            let token = load_fresh_jwt().await?;            Ok(AuthProvider::jwt_token(token))        })    }} let client = KalamLinkClient::builder()    .base_url("http://localhost:2900")    .auth_provider(Arc::new(TokenStore { /* ... */ }))    .build()?;

The provider is invoked when the client needs fresh credentials for connect or reconnect.

Shared client in a Tokio service

RUST
use std::sync::Arc;use kalam_client::{AuthProvider, KalamLinkClient}; async fn run_service() -> Result<(), Box<dyn std::error::Error>> {    let client = Arc::new(        KalamLinkClient::builder()            .base_url("http://localhost:2900")            .auth_provider(Arc::new(my_token_store))            .build()?,    );     client.connect().await?;     let worker = {        let client = Arc::clone(&client);        tokio::spawn(async move {            run_live_loop(&client).await        })    };     worker.await??;    client.disconnect().await;    Ok(())}

Refresh without rebuilding the client

When you control token rotation in application code:

RUST
let fresh = client.fresh_auth().await?; // re-runs DynamicAuthProvider if configuredclient.update_shared_auth(fresh);

Or push a known token:

RUST
client.update_shared_auth(AuthProvider::jwt_token(new_token));

Pair with auth_refresher on the builder for automatic TOKEN_EXPIRED recovery during queries — see Authentication.

When to call connect()

  • HTTP-only workers — skip connect() if you only call execute_query.
  • Live-query services — call connect() before the first live() / live_events() so all subscriptions share one socket.
  • Eager warm-up — set ConnectionOptions::default().with_ws_lazy_connect(false) on the builder if the first subscription must not pay socket setup latency.

Next

Last updated on