Skip to content

Identify your users

Only members read and write in a Komozu chat. Your server stays in charge: it creates each member once, and Komozu gives it a token for that member. The chat shows the member’s name and avatar, opens Members and Private channels to them, and lets you ban them. Without a token, the chat asks the visitor to sign in on your site.

Your server ── members.upsert({ id, name, avatarUrl }) ──▶ Komozu ──▶ { member, token } (once, at sign-up)
Your server ── writes the stored token in the page ──▶ the chat (every page)
Terminal window
npm install @komozu/node
import { Komozu } from '@komozu/node';
const komozu = new Komozu({ secretKey: process.env.KOMOZU_SECRET_KEY });

The secret key (kz_sec_…) is in the dashboard → API keys (shown once; rotate it to get a new one). Never put it in a browser or a mobile app: the API refuses any server call that carries an Origin header (403 SECRET_KEY_IN_BROWSER).

When a user signs up:

const { token } = await komozu.members.upsert({ id: user.id, name: user.name, avatarUrl: user.avatarUrl ?? null });
// Save it with the user in your database, next to their other fields
await saveUser({ ...user, komozuToken: token });
  • id is the user id in your database (1–128 characters).
  • The name (1–64 characters) and avatar shown in the chat always come from here, never from the token. The avatar is an https:// image URL.
  • The token doesn’t expire. Store it once and reuse it on every page.
  • When the name or avatar changes, call komozu.members.update(user.id, { name, avatarUrl }): the token stays the same.
  • Users who signed up before you added Komozu: run upsert once for each of them (a small script) and store their tokens.

Your server writes the signed-in user’s token in the integration’s script (data-komozu-token), and leaves it empty for a visitor who isn’t signed in (the chat then asks to sign in).

import { createServer } from 'node:http';
createServer(async (req, res) => {
const user = await getSignedInUser(req); // your own session, null for a visitor
res.setHeader('Content-Type', 'text/html; charset=utf-8');
res.end(`<!doctype html>
<h1>Club news</h1>
<script src="https://embed.komozu.com/komozu-embed.js" data-komozu-integration="int_…"
data-komozu-token="${user?.komozuToken ?? ''}" defer></script>`);
}).listen(3000);

The token never goes in a URL: the script hands it to the chat with postMessage, so it doesn’t end up in the browser history or in a Referer header.

The same token works with the developer SDKs:

  • React: <KomozuChat clientId="kz_live_…" channel="general" token={user?.komozuToken ?? null} />
  • JavaScript: new KomozuClient({ apiUrl, clientId, memberToken: user.komozuToken })

With the script, a user who signs in or out without reloading the page: window.Komozu.setUser({ token }), or window.Komozu.setUser({ token: null }) to sign out of the chat (in React, change the token prop).

A token leaked, or a user lost access to their account? Revoke their tokens:

const token = await komozu.members.revokeTokens(user.id);
await saveUser({ ...user, komozuToken: token }); // store the new one

Every token issued before stops working right away (401 TOKEN_REVOKED) and the member’s open chats are disconnected. You can also do it from the dashboard: Members → Token → Revoke tokens.

You can also create a member by hand in the dashboard (Members → New member), for example to open a private channel to a few people. Their token is shown right after, and any time from Members → Token: your server still writes it in the page.

Members → Edit changes a member’s name and avatar; open chats show the change right away. If your backend syncs its users with members.upsert, its next call can replace them.

  • A token is always required to read or write: without one, the API answers 401 MEMBER_TOKEN_REQUIRED and the chat asks to sign in, without loading any message.
  • A valid token for a member that was never created is refused (401 MEMBER_NOT_FOUND).
  • Order of checks: signature (401 INVALID_MEMBER_TOKEN) → expiry, only if the token has one (401 TOKEN_EXPIRED) → known member (401 MEMBER_NOT_FOUND) → not revoked (401 TOKEN_REVOKED) → not banned (403 MEMBER_BANNED) → channel access (403 CHANNEL_ACCESS_DENIED).
  • A token that is present but refused is never ignored: the chat says the session has ended.
  • Rotating the secret key invalidates every token signed with the old one: create new ones with upsert.
const team = await komozu.channels.create({ name: 'U15 team', access: 'private' });
await komozu.channels.addMembers(team.slug, ['user_42', 'user_43']);
await komozu.channels.removeMembers(team.slug, ['user_43']); // their open chat is disconnected right away

Members can also be added from the dashboard (channel page → Members). See server-api.md.