Who this is for
You run Jitsi Meet and want people to sign in with your company identity provider (Keycloak, Microsoft Entra ID, Authentik or any OpenID Connect provider) before they can start a meeting. Guests should still be able to join once a host is there. You want this to work in the browser and in the Jitsi mobile apps.
How it works
Jitsi only understands its own JWT. Prosody’s token plugin checks a JWT when the browser connects. The token is passed as the token parameter of the BOSH or WebSocket URL, and Jitsi Meet takes it from the page URL as ?jwt=. Prosody verifies the signature with app_secret (HS256), or with a public key from asap_key_server or cache_keys_url (RS256, needs a kid header). It then checks iss, aud, room, sub and exp.
Why an OIDC token does not just work. An identity provider’s id_token is signed with the provider’s keys, not your app secret. It has no room claim, and it comes back in the URL fragment (#id_token=) or a form POST, which Jitsi does not read. Native OIDC redirect support was requested in jitsi-meet issue #16576. A maintainer said in January 2026 that an intermediate step would still be needed. The issue was closed as stale on 2026-03-29.
Bridge patterns. Issue #16576 lists three:
- Adapter or token service (recommended). A small service runs the OIDC login, then signs a Jitsi JWT with your app secret.
jitsi-contrib/jitsi-oidc-adapteris the maintained community option. The oldernordeck/jitsi-keycloak-adapterREADME now tells users to switch to it. - Prosody verifies the provider’s token directly. Since PR #16649 (2.0.10655),
cache_keys_urlaccepts a JWKS URL. You still need a page that copies the fragment token into?jwt=, the implicit flow, andasap_require_room_claim = false. - Pre-signed links from your own app. These suit portals and bots, not interactive sign-in.
A reverse proxy login (for example in front of the web page) is not enough on its own. Prosody still needs a JWT on the XMPP connection.
The login redirect. When a user who is not signed in needs to log in, Jitsi Meet sends them to tokenAuthUrl. It fills in {room} and {state}; state holds the room, tenant, config overrides and ios=true, android=true or electron=true. Without tokenAuthUrl, Jitsi shows the username and password dialog instead. The mobile apps open tokenAuthUrl in the system browser and wait for a deep link that carries the JWT back. The adapter returns org.jitsi.meet:// links for iOS, an Android intent:// link, and jitsi-meet:// for the Electron app.
Who becomes moderator. In Docker, JICOFO_ENABLE_AUTH defaults to ENABLE_AUTH, and the Jicofo auth type follows AUTH_TYPE. So with AUTH_TYPE=jwt, Jicofo authentication is on. Jicofo then grants owner (moderator) to every authenticated member. Guests join on the anonymous domain and are not authenticated. To decide moderators from a token claim, the bundled mod_token_affiliation reads context.user.moderator (true or "true") or context.user.affiliation (owner, moderator, teacher).
Before you start
- Jitsi with HTTPS at
https://meet.example.com: docker-jitsi-meet stable-11248 or packages 2.0.11248. - An OIDC provider reachable by users and by the adapter. Keycloak 26.8.0 is current as of 2026-10-01.
- A random app secret shared by the adapter and Prosody, for example
openssl rand -hex 32. - For Keycloak: a realm (here
example) and admin access. The issuer ishttps://auth.example.com/realms/example. - For Entra ID: an app registration. The issuer is
https://login.microsoftonline.com/<tenant-id>/v2.0.
Steps
1. Create the OIDC client
Keycloak (adapter docs):
- Create a client, for example
jitsi. - Valid redirect URIs:
https://meet.example.com/oidc/tokenize - Web origins:
https://meet.example.com - Either turn off Client authentication (public client), or leave it on and copy the client secret.
Entra ID: register a web app with redirect URI https://meet.example.com/oidc/tokenize and create a client secret. The adapter reads endpoints from the issuer’s discovery document. Entra’s discovery document lists a userinfo endpoint. This path is untested (see Open questions).
2. Docker (docker-jitsi-meet stable-11248)
Add the adapter as a service in docker-compose.override.yml. Compose merges that file automatically:
services:
oidc-adapter:
image: ghcr.io/jitsi-contrib/jitsi-oidc-adapter
restart: unless-stopped
environment:
- OIDC_ISSUER_URL=https://auth.example.com/realms/example
- OIDC_CLIENT_ID=jitsi
- OIDC_CLIENT_SECRET=${OIDC_CLIENT_SECRET}
- JWT_APP_ID=${JWT_APP_ID}
- JWT_APP_SECRET=${JWT_APP_SECRET}
- JWT_EXP_SECOND=3600
- AUTO_RETURN_TO_APP=true
networks:
meet.jitsi:
web:
depends_on:
- oidc-adapterThe variable names and the port (9000) come from the adapter image. The adapter’s own Docker guide publishes port 9000 on the host instead and is marked “NOT READY YET”.
Proxy /oidc/ through Jitsi’s web container. Create ~/.jitsi-meet-cfg/web/nginx-custom/oidc.conf. The stable-11248 web image copies /config into /run/web/config and includes nginx-custom/*.conf:
location ~ /oidc/ {
proxy_pass http://oidc-adapter:9000;
proxy_http_version 1.1;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header Host $http_host;
}Keep the Host header: the adapter builds https://<host>/oidc/tokenize from it.
Set .env:
ENABLE_AUTH=1
AUTH_TYPE=jwt
JWT_APP_ID=meet_example
JWT_APP_SECRET=REPLACE_WITH_RANDOM_SECRET
OIDC_CLIENT_SECRET=REPLACE_WITH_CLIENT_SECRET
ENABLE_GUESTS=1
TOKEN_AUTH_URL=https://meet.example.com/oidc/auth?state={state}
XMPP_MODULES=persistent_lobby
XMPP_MUC_MODULES=muc_wait_for_hostTOKEN_AUTH_URL becomes config.tokenAuthUrl. ENABLE_GUESTS adds the anonymousdomain, so guests can wait for a host.
Start it:
docker compose up -d3. Debian/Ubuntu packages (2.0.11248)
-
Install token support. It asks for the app ID and secret and sets
authentication = "token":Terminalsudo apt-get install jitsi-meet-tokens -
Add the guest VirtualHost to the Prosody config, and
anonymousdomainto/etc/jitsi/meet/meet.example.com-config.js:LuaVirtualHost "guest.meet.example.com" authentication = "jitsi-anonymous" c2s_require_encryption = falseJavaScriptanonymousdomain: 'guest.meet.example.com', -
Add
persistent_lobbyto the main VirtualHostmodules_enabled, andmuc_wait_for_hostto theconferencecomponent. -
Install the adapter as a systemd service. Proxy
/oidc/tohttp://127.0.0.1:9000with the adapter’soidc.confin/etc/jitsi/meet/jaas/. -
Set the login URL in
/etc/jitsi/meet/meet.example.com-config.js:JavaScriptconfig.tokenAuthUrl = 'https://meet.example.com/oidc/auth?state={state}'; -
Restart:
Terminalsudo systemctl restart prosody jicofo jitsi-videobridge2 nginx
4. Choose how moderators are decided
- Every signed-in user is a moderator (Docker default). Leave Jicofo auth on.
- Only some users are moderators. Add
moderator: trueundercontext.userfor chosen users. The adapter buildscontext.userinsrc/context.ts. Then loadtoken_affiliationand stop Jicofo from promoting everyone. In Docker that meansXMPP_MUC_MODULES=muc_wait_for_host,token_affiliation,JICOFO_ENABLE_AUTH=0,ENABLE_AUTO_OWNER=0andWAIT_FOR_HOST_DISABLE_AUTO_OWNERS=1. We derived this from source, so test it first.
5. Direct JWKS verification (alternative, packages)
Packages 2.0.10655 and newer can verify Keycloak tokens without an adapter. A maintainer gave this Prosody setup in #16576:
asap_accepted_issuers = { "https://auth.example.com/realms/example" }
asap_accepted_audiences = { "jitsi" }
asap_require_room_claim = false;
VirtualHost "meet.example.com"
authentication = "token"
cache_keys_url = "https://auth.example.com/realms/example/protocol/openid-connect/certs";You also need a plugin.head.html script that turns #id_token= into ?jwt=, plus the implicit flow. Keycloak warns that implicit-flow tokens are “very hard to invalidate”. docker-jitsi-meet has no cache_keys_url variable.
Configuration reference
| Name | Where | Default | What it does |
|---|---|---|---|
ENABLE_AUTH |
Docker .env |
0 |
Turns on authentication |
AUTH_TYPE |
Docker .env |
internal |
jwt selects token auth |
JWT_APP_ID |
Docker .env |
unset | Prosody app_id. Default accepted issuer |
JWT_APP_SECRET |
Docker .env |
unset | Prosody app_secret, HS256 key |
JWT_ACCEPTED_ISSUERS / JWT_ACCEPTED_AUDIENCES |
Docker .env |
issuers: app ID; audiences: * |
Allowed iss and aud |
JWT_ENABLE_DOMAIN_VERIFICATION |
Docker .env |
false |
When on, sub must equal XMPP_DOMAIN (default meet.jitsi) or * |
JWT_ALLOW_EMPTY |
Docker .env |
0 |
Lets users connect without a token |
ENABLE_GUESTS |
Docker .env |
0 |
Adds the anonymous guest domain |
TOKEN_AUTH_URL |
Docker .env |
unset | Sets config.tokenAuthUrl |
JICOFO_ENABLE_AUTH |
Docker .env |
value of ENABLE_AUTH |
Jicofo auth. When on, every authenticated user is moderator |
ENABLE_AUTO_OWNER |
Docker .env |
Jicofo default | First member becomes moderator when Jicofo auth is off |
JICOFO_AUTH_LIFETIME |
Docker .env |
24 hours |
Jicofo auth session lifetime |
XMPP_MODULES / XMPP_MUC_MODULES |
Docker .env |
unset | Extra Prosody modules |
tokenAuthUrl |
config.js |
unset | Login service URL with {room}, {state}, {code_challenge} |
tokenLogoutUrl |
config.js |
unset | Logout service URL |
cache_keys_url |
Prosody VirtualHost | unset | JWKS URL for RS256 tokens, 2.0.10655+ |
asap_require_room_claim |
Prosody | true |
Requires the room claim |
OIDC_ISSUER_URL, OIDC_CLIENT_ID, OIDC_CLIENT_SECRET, OIDC_SCOPES |
adapter env | client jitsi, scopes openid profile email |
Provider settings |
JWT_EXP_SECOND |
adapter env | 10800 |
Lifetime of minted Jitsi tokens |
AUTO_RETURN_TO_APP |
adapter env | false |
Redirect mobile and desktop apps back automatically |
Claims the adapter puts in its token: aud and iss = JWT_APP_ID; sub = the tenant or meeting host; room = the requested room; iat, nbf, exp; context.user with id (the OIDC sub), name, email, lobby_bypass and security_bypass.
Common mistakes
- Pasting the provider’s token as
?jwt=while Prosody usesapp_secret. Prosody logsError verifying token err:not-allowed, reason:Invalid signature. - Putting the token in the fragment. Jitsi parses hash values as JSON, so
#jwt=needs the value in quotes.?jwt=does not. - Setting
tokenAuthUrlAutoRedirect. The adapter docs set it, but it is not in jitsi-meet’s config type on master as of 2026-10-05. - Everyone is a moderator. That is Jicofo auth with the Docker defaults. See step 4.
'kid' claim is missingafter addingcache_keys_url. With a key URL set, Prosody verifies only RS-signed tokens withkid, so HS256 tokens from other tools fail.Room does not match the room from token. The adapter scopes each token to one room, so the same link cannot open another room.- Wrong
subwith domain verification on. On Docker,submust bemeet.jitsi(XMPP_DOMAIN) or*. With the Docker default (off),subis only required to exist. On packages, the domain is your public hostname. - Redirect URI mismatch in Keycloak. It must be exactly
https://meet.example.com/oidc/tokenize. - Proxy drops the
Hostheader, so the adapter builds a wrong redirect URI.
Verify
-
Adapter health. The adapter answers on
/oidc/health:Terminalcurl -s https://meet.example.com/oidc/healthExpect
healthy. -
The adapter found the provider. At startup,
docker compose logs oidc-adaptershowsAUTH_ENDPOINT:,TOKEN_ENDPOINT:andUSERINFO_ENDPOINT:lines. -
Open
https://meet.example.com/testroomin a private window. Click the log-in button on the wait-for-host screen. You should go to Keycloak, then back to/testroom?jwt=.... -
Decode the token’s middle part and confirm
roomistestroom,audandissequalJWT_APP_ID, andexpis about one hour ahead. -
In a second browser, open the same room without signing in. The guest should wait until the host is in, then join without moderator rights.
If it still fails
- Prosody:
docker compose logs prosody | grep -i token. Look forError verifying tokenwith a reason such asInvalid signature,room claim is missingortoken required. - Jicofo:
docker compose logs jicofo | grep -i ownershipshowsGranting ownership tofor each promoted user. - Adapter:
docker compose logs oidc-adapter. Discovery or userinfo errors point atOIDC_ISSUER_URLor the client secret. - Mobile app does not return: test with Firefox on Android. The adapter docs report a “broken tab” problem with Chromium browsers when
AUTO_RETURN_TO_APP=true.
What we have not confirmed yet
We checked everything above against the Jitsi token library, Jicofo, the docker-jitsi-meet templates, the adapter source and maintainer comments on 2026-10-05. We have not yet run the full Keycloak or Entra ID flow on stable-11248. These points are still open:
- The adapter’s Docker guide says “NOT READY YET” and was tested with stable-10741. The standalone guide was tested on Debian 12 with 2.0.10741. Neither is confirmed on 11248.
- The compose override (adapter on the
meet.jitsinetwork, proxy tooidc-adapter:9000) is our adaptation of the adapter docs. Untested. - Claim-based moderators: the combination
JICOFO_ENABLE_AUTH=0,ENABLE_AUTO_OWNER=0,WAIT_FOR_HOST_DISABLE_AUTO_OWNERS=1andtoken_affiliationis derived from source and needs a real test. Includes whether the wait-for-host login still triggers with Jicofo auth off. - Nothing in jitsi-meet’s Prosody plugins reads the adapter’s
lobby_bypassandsecurity_bypassflags (code search, 2026-10-05). Their effect is unconfirmed. - Entra ID with the adapter: discovery and userinfo should work, but untested. Entra’s multi-tenant discovery uses
{tenantid}in the issuer, so use the tenant-specific issuer URL. - Direct JWKS on Docker:
XMPP_CONFIGURATIONlines are rendered into the main VirtualHost, socache_keys_urlcould be added that way. Untested. - When
tokenAuthUrlAutoRedirectwas removed from jitsi-meet, and whether it had any replacement. - White-label mobile apps use their own URL scheme. The adapter hardcodes
org.jitsi.meetandjitsi-meet. - Tokens travel in the page URL (
?jwt=), so they can appear in browser history. Whether the default nginx access log records them was not checked.
Sources
- Jitsi handbook, Token Authentication, checked 2026-10-05, official doc
- lib-jitsi-meet doc/tokens.md, JWT authentication Prosody plugin, checked 2026-10-05, official doc
- Jitsi handbook, Self-Hosting Guide: Docker (Authentication, Authentication using JWT tokens), source last changed 2026-10-02, official doc
- jitsi-meet issue #16576 Native OpenID Connect (OIDC) redirect support, 2025-10-22 to 2026-03-29 (closed as stale), maintainer comments (damencho, aaronkvanmeerten) and community reports
- jitsi-meet PR #16649 feat(jwt): Supports JWKS endpoint, merged 2025-11-17, first in 2.0.10655, maintainer PR
- jitsi-meet resources/prosody-plugins/token/util.lib.lua, checked 2026-10-05, source code
- docker-jitsi-meet prosody/rootfs/defaults/conf.d/jitsi-meet.cfg.lua at stable-11248, source code
- docker-jitsi-meet jicofo/rootfs/defaults/jicofo.conf at stable-11248, source code
- jicofo ChatRoomRoleManager.kt (AuthenticationRoleManager, AutoOwnerRoleManager) and JitsiMeetConferenceImpl.java, checked 2026-10-05, source code
- jitsi-meet resources/prosody-plugins/mod_token_affiliation.lua, in 2.0.10978 and newer, source code
- jitsi-meet config.js (tokenAuthUrl, tokenLogoutUrl, tokenAuthInline), checked 2026-10-05, source code
- jitsi-meet react/features/authentication (functions.any.ts, functions.native.ts, actions.native.ts, middleware.any.ts) and base/config/configType.ts, checked 2026-10-05, source code
- jitsi-contrib/jitsi-oidc-adapter README, docs/setup-docker.md and docs/setup-standalone.md, release v20260328, community project
- jitsi-contrib/jitsi-oidc-adapter src/adapter.ts, src/config.ts, src/context.ts and Dockerfile, v20260328, community source code
- nordeck/jitsi-keycloak-adapter README, release v20260623, community project
- docker-jitsi-meet web templates at stable-11248 (system-config.js, settings-config.js, meet.conf, s6 config script), source code
- docker-jitsi-meet docker-compose.yml at stable-11248, 2026-09-14, source code
- Keycloak, Securing applications: OpenID Connect layers (endpoints, implicit flow), Keycloak 26.8.0 released 2026-10-01, official doc
- Microsoft Entra ID token claims reference and v2.0 OpenID configuration, and https://login.microsoftonline.com/common/v2.0/.well-known/openid-configuration, checked 2026-10-05, official doc
- Docker docs, Merge Compose files, official doc (Docker)
- jitsi-meet doc/debian/jitsi-meet-prosody/prosody.cfg.lua-jvb.example (muc_mapper_domain_base), source code
Need a hand?
Single sign-on touches your identity provider, Prosody and Jicofo at once. Our integration service sets it up and tests host, guest and mobile logins, or contact our engineers with the Prosody lines that mention Error verifying token.