JWT authentication turns Jitsi Meet from “anyone who guesses the URL can join” into “only people your application approves can join”. Your backend signs a short-lived token for each user, and Jitsi checks it before letting them in. It is the standard way to embed Jitsi into a product, a course platform or a telehealth app.
This guide matches the configuration our platform enables for customers on stable-11031.
How it works
- Your app decides a user may join room
team-standup. - Your server signs a token with the shared secret.
- The user opens
https://meet.example.com/team-standup?jwt=<token>. - Prosody validates the signature, expiry, issuer, audience, domain and room, then admits the user.
1. Enable JWT in Docker
In .env:
ENABLE_AUTH=1
AUTH_TYPE=jwt
JWT_APP_ID=my_app
JWT_APP_SECRET=use-a-long-random-secret
JWT_ACCEPTED_ISSUERS=my_app
JWT_ACCEPTED_AUDIENCES=my_app
# 1 lets people without a token join rooms that already exist.
ENABLE_GUESTS=1
Generate the secret with something like openssl rand -hex 32. Then recreate the containers so Prosody picks up the new auth settings:
docker compose up -d --force-recreate
2. The token format
Header: {"alg": "HS256", "typ": "JWT"}
Payload:
{
"iss": "my_app",
"aud": "my_app",
"sub": "meet.example.com",
"room": "team-standup",
"exp": 1790000000,
"context": {
"user": {
"id": "user-42",
"name": "Priya Sharma",
"email": "priya@example.com",
"avatar": "https://example.com/avatars/42.png",
"moderator": true
}
}
}
| Claim | Must be | Notes |
|---|---|---|
iss |
Your JWT_APP_ID |
Checked against JWT_ACCEPTED_ISSUERS |
aud |
Your JWT_APP_ID |
Checked against JWT_ACCEPTED_AUDIENCES |
sub |
Your Jitsi domain | The public hostname, not the internal meet.jitsi |
room |
Room name or * |
Lowercase room names avoid case mismatches |
exp |
Future Unix time | Keep it short, for example one hour |
context.user |
Display details | name pre-fills the display name |
3. Sign tokens in your backend
Node.js
import jwt from "jsonwebtoken";
export function jitsiToken({ room, user, moderator }) {
return jwt.sign(
{
iss: process.env.JWT_APP_ID,
aud: process.env.JWT_APP_ID,
sub: "meet.example.com",
room,
context: { user: { id: user.id, name: user.name, email: user.email, moderator } },
},
process.env.JWT_APP_SECRET,
{ algorithm: "HS256", expiresIn: "1h" },
);
}
Python
from datetime import datetime, timedelta, timezone
import jwt # PyJWT
def jitsi_token(room: str, user: dict, moderator: bool) -> str:
payload = {
"iss": APP_ID,
"aud": APP_ID,
"sub": "meet.example.com",
"room": room,
"exp": datetime.now(timezone.utc) + timedelta(hours=1),
"context": {"user": {"id": user["id"], "name": user["name"], "moderator": moderator}},
}
return jwt.encode(payload, APP_SECRET, algorithm="HS256")
Then send the user to https://meet.example.com/{room}?jwt={token}, or pass the token to the IFrame API as the jwt option.
4. Moderators and guests
With JWT enabled, token holders are authenticated users and can start rooms. With ENABLE_GUESTS=1, people without a token can join a room after it has started, as guests.
Recent releases read context.user.moderator to decide who gets moderator rights. Whether that flag is enforced depends on the Prosody modules active on your server, so test with two browsers: one host token with moderator: true and one guest token with false. If both end up as moderators, your release is promoting every authenticated user, and you need the token affiliation module or a newer release.
5. Embed with the IFrame API
<script src="https://meet.example.com/external_api.js"></script>
<div id="meet" style="height: 600px"></div>
<script>
const api = new JitsiMeetExternalAPI("meet.example.com", {
roomName: "team-standup",
jwt: TOKEN_FROM_YOUR_SERVER,
parentNode: document.getElementById("meet"),
});
</script>
Common mistakes
subset to the internal domain. Use the public hostname users type.- Clock skew. If the server clock is behind, fresh tokens look not-yet-valid. Keep NTP running.
- Tokens signed in the browser. The secret leaks with the page source.
- Room case.
Standupin the URL andstandupin the token can mismatch. Use lowercase everywhere.
Full error list: Jitsi JWT not working.
Want it done for you?
Our platform enables JWT per server and gives you a test token and host links from the dashboard, and our team integrates Jitsi JWT into existing apps as a service.