Skip to content
Jitsi.help

Jitsi Meet JWT authentication

Updated Tested on Jitsi Meet stable-11031By the Jitsi Help engineering team

Short answer

Set ENABLE_AUTH=1, AUTH_TYPE=jwt, JWT_APP_ID and JWT_APP_SECRET in the Docker .env, restart, then sign HS256 tokens whose iss and aud are your app ID, sub is your Jitsi domain, room is the room name (or *), and exp is in the future. Users join with https://meet.example.com/Room?jwt=TOKEN.

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

  1. Your app decides a user may join room team-standup.
  2. Your server signs a token with the shared secret.
  3. The user opens https://meet.example.com/team-standup?jwt=<token>.
  4. 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

  • sub set 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. Standup in the URL and standup in 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.

Frequently asked questions

What claims does a Jitsi JWT need?

iss and aud set to your JWT_APP_ID, sub set to your Jitsi domain (for example meet.example.com), room set to the room name or * for any room, and exp as a Unix timestamp in the future. User details go under context.user.

Can guests join without a token?

Yes, if ENABLE_GUESTS=1. Token holders create and moderate rooms, and people without a token can join a room once it exists. Set ENABLE_GUESTS=0 to require a token for everyone.

Which algorithm does Jitsi use for JWT?

HS256 with a shared secret (JWT_APP_SECRET) is the common setup and what we use. RS256 with public keys is also supported for larger integrations where the signing key must stay on another system.

Is the JWT secret safe in the browser?

No. Always sign tokens on your server and send only the finished token to the browser. Anyone who has the secret can mint tokens for any room.

Stuck, or would rather not do this by hand?

Deploy it in one click

A private Jitsi server in your own AWS account with SSL, your domain and optional recording, transcription and JWT. Free 15 minute trial.

Start free trial

Talk to a Jitsi engineer

Setup, fixes, branding, recording, scaling. Tell us what is happening and we reply with a plan and a quote.

Get expert help

Related