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)
| Token | Who issues it | Where it lives | Purpose |
|---|---|---|---|
A — Session token (sessionToken) | Your auth (Supabase, Firebase, Cognito, your JWT login, etc.) | Mobile app after the user signs in | Proves the user is logged into your product |
| B — Calling token | Alaznah (minted by your backend, or Console Test Token) | Returned from getAuthToken() to the SDK | Proves 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
User logs into YOUR app
sessionToken (your auth)
Issued by your login — Supabase, Firebase, your JWT, etc.
App → YOUR backend
GET/POST /calling/token
Authorization: Bearer <sessionToken>
YOUR backend → Alaznah
POST https://www.alaznah.com/api/v1/calling/token
Authorization: Bearer ac_live_…
Body: { "userId": "alice", "ttlSeconds": 900 }
Calling JWT → app → CallingProvider getAuthToken()
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.
<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)
POST /calling/token
Authorization: Bearer <sessionToken>Your server should:
- Validate
sessionTokenwith your auth (reject if invalid / expired). - Resolve the logged-in user’s stable id → use that as Alaznah
userId. - Call Alaznah mint with the server API key.
- Return
{ "token": "<calling-jwt>" }to the app.
Response (your server → app)
{ "token": "eyJhbGciOi..." }Pseudo-code:
// 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).
POST https://www.alaznah.com/api/v1/calling/token
Authorization: Bearer ac_live_YOUR_API_KEY
Content-Type: application/json
{ "userId": "alice", "ttlSeconds": 900 }| Field | Required | Notes |
|---|---|---|
Authorization | Yes | Bearer ac_live_… from Developer Console → API keys |
userId | Yes | End-user id peers will dial; must match SDK config.userId |
ttlSeconds | No | Short 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:
- Open Console → Tokens
- Pick project · enter
userId· generate · copy JWT - 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
userIdper 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
- Quick Start — first call wiring
- Hosted Signaling
- Client Methods —
connect, events - Troubleshooting — auth / 401