Alaznah

Two-token model, sessionToken, and how to mint Alaznah calling JWTs.

Authentication

Alaznah Calling does not log users into your app. Your app already has a login. Alaznah only needs a short-lived calling JWT so the SDK can connect to signaling.

Never ship ac_live_… API keys or secrets inside the mobile binary.

Two tokens (do not mix them)

TokenWho issues itWhere it livesPurpose
A — Session token (sessionToken)Your auth (Supabase, Firebase, Cognito, your JWT login, etc.)Mobile app after the user signs inProves the user is logged into your product
B — Calling tokenAlaznah (minted by your backend, or Console Test Token)Returned from getAuthToken() to the SDKProves the client may join Hosted Signaling as userId

sessionToken is never created by Alaznah. If your app already stores an access token after login, that value (or whatever you send to your API as Authorization) is your sessionToken.

Token flow

  1. User logs into YOUR app

  2. sessionToken (your auth)

    Issued by your login — Supabase, Firebase, your JWT, etc.

  3. App → YOUR backend

    GET/POST /calling/token

    Authorization: Bearer <sessionToken>

  4. YOUR backend → Alaznah

    POST https://www.alaznah.com/api/v1/calling/token

    Authorization: Bearer ac_live_…

    Body: { "userId": "alice", "ttlSeconds": 900 }

  5. Calling JWT → app → CallingProvider getAuthToken()

  6. SDK connects to Hosted Signaling

    wss://signal.alaznah.com

The userId in the calling JWT must match CallingProvider config.userId.


What the mobile app calls

The app calls your API only — not Alaznah’s mint URL with the secret key.

tsx
<CallingProvider
  config={{
    userId: currentUser.id, // same id you mint for
    getAuthToken: async () => {
      // sessionToken = whatever YOUR login already gave you
      const res = await fetch('https://api.yourapp.com/calling/token', {
        headers: { Authorization: `Bearer ${sessionToken}` },
      });
      if (!res.ok) throw new Error('Failed to mint calling token');
      const { token } = await res.json();
      return token; // Alaznah calling JWT
    },
    // signalingUrl omitted → Hosted Signaling default
  }}
/>

Example: your backend route

Path and framework are up to you. Contract the app expects:

Request (from app → your server)

http
POST /calling/token
Authorization: Bearer <sessionToken>

Your server should:

  1. Validate sessionToken with your auth (reject if invalid / expired).
  2. Resolve the logged-in user’s stable id → use that as Alaznah userId.
  3. Call Alaznah mint with the server API key.
  4. Return { "token": "<calling-jwt>" } to the app.

Response (your server → app)

json
{ "token": "eyJhbGciOi..." }

Pseudo-code:

ts
// YOUR backend — never expose ac_live_ to the client
app.post('/calling/token', async (req, res) => {
  const sessionUser = await validateYourSession(req.headers.authorization);
  if (!sessionUser) return res.status(401).json({ error: 'unauthorized' });

  const mint = await fetch('https://www.alaznah.com/api/v1/calling/token', {
    method: 'POST',
    headers: {
      Authorization: `Bearer ${process.env.ALAZNAH_API_KEY}`, // ac_live_...
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({
      userId: sessionUser.id,
      ttlSeconds: 900,
    }),
  });

  if (!mint.ok) {
    return res.status(502).json({ error: 'mint failed' });
  }

  const data = await mint.json();
  // Return the JWT string your SDK expects (field name may be `token` — match your client parse)
  return res.json({ token: data.token ?? data.jwt ?? data });
});

Adjust the response-field mapping to match the JSON your Alaznah mint actually returns (Console / API docs for your account).


Alaznah mint endpoint (server → Alaznah)

Use this only on your backend (or via Console Test Token for demos).

http
POST https://www.alaznah.com/api/v1/calling/token
Authorization: Bearer ac_live_YOUR_API_KEY
Content-Type: application/json

{ "userId": "alice", "ttlSeconds": 900 }
FieldRequiredNotes
AuthorizationYesBearer ac_live_… from Developer Console → API keys
userIdYesEnd-user id peers will dial; must match SDK config.userId
ttlSecondsNoShort TTL recommended (e.g. 60–3600)

Typical errors: 401 invalid key · 403 project/account · 402 trial ended · 429 trial mint cap.

Get the key: Console → create project → copy API key into server env only.


Dev without a backend — Console Test Token

For Quick Start on two devices before you build /calling/token:

  1. Open Console → Tokens
  2. Pick project · enter userId · generate · copy JWT
  3. Temporarily return that string from getAuthToken

Mint a separate token per device / userId. Tokens expire — regenerate when signaling auth fails.

Do not ship a hard-coded JWT in production builds.


Rules of thumb

  • Return a fresh calling token from getAuthToken() when possible (do not cache forever)
  • Keep TTL short (minutes, not days)
  • On signaling 401 / reconnect exhausted, mint again and reconnect
  • One stable userId per end user; never reuse the same JWT as two different people
  • sessionToken → your API; ac_live_… → Alaznah mint only

Entitlement (commercial)

Separately from end-user JWT auth, the SDK may validate a developer entitlement / feature session via entitlementProvider. Local development falls back to a trial provider when omitted. Production apps should follow console guidance for paid plans.

Next