ابرووا
شروع رایگان
☰ فهرست مستندات · احراز هویت
به‌زودی. Abrova Chat به‌زودی فعال می‌شود. این صفحه توضیح می‌دهد چطور کار خواهد کرد؛ هنوز قابل استفاده نیست.
این صفحه هنوز ترجمه نشده — نسخه‌ی انگلیسی نمایش داده می‌شود. English

Authentication

Prove who your users are with short-lived user tokens minted by your server — Flutter, iOS, Android, React Native, Web, Node.js, REST. Automatic refresh, revocation on logout, and strict mode.

به‌روزرسانی: ۵ آبان ۱۴۰۵

Your API key identifies your project, not your user. It ships inside every app and web bundle, so anyone can extract it. To let AbrovaChat trust who is acting, your server issues a short-lived user token and the SDK sends it with every request.

This is the same model used by other chat platforms: your backend vouches for the user, the client never holds a secret.

Existing apps keep working.

User tokens are opt-in. Without a tokenProvider the SDK uses the legacy mode (API key + userId), exactly as before. Add tokens when you are ready, then switch your project to strict mode.

The three credentials#

CredentialLives inProvesIf leaked
API key (ab_live_…)Your app, publicWhich projectHarmless in strict mode: it cannot act as a user
Server secret (ab_srv_…)Your server onlyThat your backend is callingSerious — rotate it in Abrova Console
User token (JWT, 1 h)Your app, per userWhich userLimited: one user, one project, expires, and you can revoke it

Mint tokens on your server#

Add one endpoint, protected by your own login, that returns a token for the signed-in user.

Node.js

typescript
import { AbrovaChat } from '@abrova/chat';

const chat = new AbrovaChat({
  apiKey: process.env.ABROVA_API_KEY!,
  serverSecret: process.env.ABROVA_SERVER_SECRET!, // server-side only
});

// Express — requireLogin is YOUR auth middleware
app.get('/chat-token', requireLogin, async (req, res) => {
  const { token, expiresAt } = await chat.users.createToken({
    userId: req.user.id,                       // your own user id
    info: { displayName: req.user.name },      // optional, shown to other clients
  });
  res.json({ token, expiresAt });
});

REST (any backend)

bash
curl -X POST https://chat.abrova.ir/api/v1/users/token \
  -H "x-api-key: $ABROVA_API_KEY" \
  -H "x-server-secret: $ABROVA_SERVER_SECRET" \
  -H "Content-Type: application/json" \
  -d '{"userId": "user-123", "ttl": 3600}'

# → { "token": "eyJhbGciOi…", "expiresAt": "2026-09-12T10:00:00.000Z", "userId": "user-123" }

ttl is in seconds: 3600 (1 hour) by default, 86400 (24 hours) maximum. Shorter is safer, and refreshing costs the client one call to your server.

Never ship the server secret.

The server secret can mint a token for any user. Keep it on your server, out of app bundles, mobile binaries and client-side JavaScript.

One token for every Abrova product

If your app also uses Abrova Sync, Abrova Push or Abrova A/B Testing, mint one token for all of them from the Abrova auth endpoint:

bash
curl -X POST https://auth.abrova.ir/users/token \
  -H "x-api-key: $ABROVA_API_KEY" \
  -H "x-server-secret: $ABROVA_SERVER_SECRET" \
  -H "Content-Type: application/json" \
  -d '{"userId": "user-123", "expiresIn": 3600}'

# → { "token": "eyJhbGciOi…", "userId": "user-123", "expiresIn": 3600, "expiresAt": "2026-09-21T10:00:00.000Z" }

Give that same token to every SDK's tokenProvider (or setUserToken) — Chat, Sync, Push and A/B Testing — instead of fetching one per product. expiresIn is in seconds: 3600 (1 hour) by default, 86400 (24 hours) maximum. The same rules apply: call it from your server, never from an app.

Keep it on the device.

A token is valid until it expires, so store it with the user's session (Keychain, Keystore or secure storage) and reuse it across app launches. Your app then only calls your backend when the token is close to expiry — not on every start.

Revoking a user (below) also blocks their Abrova token in Chat. It carries no info, so if other clients should see a display name from the token, mint the Chat token above instead.

Use the token in your app#

Pass a tokenProvider that calls your endpoint. The SDK caches the token, refreshes it about a minute before it expires, and retries once if the server reports an expired token — all invisible to the user.

Flutter

dart
// abrova_chat: ^0.1.5
final client = AbrovaChatClient(AbrovaChatConfig(
  apiKey: 'ab_live_your_api_key',
  userId: currentUser.id,
  tokenProvider: () => myBackend.chatToken(), // Future<String>
));

// Identity errors a refresh cannot fix (revoked, invalid, logged out).
client.onAuthError.listen((e) => signOut());

Web

typescript
// @abrova/web-chat: ^0.1.2
const client = new AbrovaChatClient({
  apiKey: process.env.NEXT_PUBLIC_ABROVA_API_KEY!,
  userId: currentUser.id,
  tokenProvider: async () => (await fetch('/chat-token')).json().then((j) => j.token),
});

client.on('authError', () => signOut());

React Native

typescript
// @abrova/react-native-chat: ^0.1.2
const client = new AbrovaChatClient({
  apiKey: ABROVA_API_KEY,
  userId: currentUser.id,
  tokenProvider: async () => {
    const res = await fetch('https://api.example.com/chat-token', {
      headers: { Authorization: `Bearer ${sessionToken}` },
    });
    return (await res.json()).token;
  },
});

client.on('authError', () => signOut());

iOS

swift
// Swift Package Manager: https://github.com/Abrova-co/abrova-chat-ios-sdk.git (0.1.4+)
let config = AbrovaChatConfig(
    apiKey: "ab_live_your_api_key",
    userId: currentUser.id,
    tokenProvider: { try await myBackend.chatToken() }
)
let client = AbrovaChatClient(config: config)

client.onAuthError
    .sink { _ in signOut() }
    .store(in: &cancellables)

Android

kotlin
// implementation("ir.abrova:abrova-chat-android:0.1.4")
val config = AbrovaChatConfig(
    apiKey = "ab_live_your_api_key",
    userId = currentUser.id,
    tokenProvider = { myBackend.chatToken() }   // suspend fun returning the token
)
val client = AbrovaChatClient(config)

scope.launch { client.onAuthError.collect { signOut() } }

REST (any HTTP client)

bash
curl https://chat.abrova.ir/api/v1/rooms \
  -H "x-api-key: $ABROVA_API_KEY" \
  -H "x-user-token: $USER_TOKEN"

Revoke on logout#

Tokens expire on their own, but revoke them when a session ends so a stolen token dies immediately.

typescript
await chat.users.revokeTokens(userId);
// REST: POST /api/v1/users/{userId}/revoke-tokens  (server secret required)

Every token issued to that user before this moment stops working, for REST and realtime alike, within a few seconds. Call it on logout, password change and ban.

What the server enforces#

Once a request carries a user token, AbrovaChat ignores any userId in the request and uses the token's user:

AttemptResult
Read or send as another user403 user_mismatch
Open a room you are not in (details, history, pinned, presence, reactions)403 not_a_participant
Edit or delete someone else's message403
Use a token from another project401 token_invalid
Use an expired token401 token_expired — the SDK refreshes and retries automatically
Use a revoked token401 token_revoked

Error codes the SDKs act on:

CodeMeaningSDK behaviour
token_expiredLifetime elapsedFetches a new token and retries the request once
token_invalidMalformed, wrong project, or not server-mintedauthError — send the user to login
token_revokedRevoked by your serverauthError
token_requiredProject is in strict mode and no token was sentauthError
token_provider_failedYour endpoint failed or is unreachableauthError

Turn on strict mode#

While a project allows the legacy mode, a request with only the API key is still accepted — which is what keeps already-released apps working. Once every live client sends tokens, enable Require signed user tokens under Chat security in your project's settings in Abrova Console.

From then on, for that project:

  • every per-user request needs a user token (or your server secret);
  • the legacy connection-token endpoint (deprecated, used only by old SDK versions) no longer issues a token to the public API key alone.
Retire old app versions first.

Apps already installed keep using the legacy mode. Enable strict mode only once those versions are gone — a force-update mechanism in your app makes that possible. Server-to-server calls with the server secret are unaffected.

Room management from your server#

Creating rooms and adding or removing participants take no acting user, so with the API key alone anyone could add themselves to a room. Do that work on your server with the server secret, then enable Server-only room management under Chat security in your project's settings in Abrova Console.

typescript
// Your server, with the server secret
const { room } = await chat.rooms.findOrCreate({
  externalId: `dm-${a}-${b}`,
  participants: [{ externalUserId: a }, { externalUserId: b }],
});

Apps keep sending messages, reading history and subscribing as usual; only room management is restricted.

این صفحه مفید بود؟
گزارش مشکل