JWT + guest auth with "Waiting for the host..." popup (no lobby)

Hello!, After enabling these two modules:



Especially on the last one i found this piece of code:

-- if the party has not started yet, don't accept the participant
    local occupant_count = it.count(room:each_occupant())
    if occupant_count < 2 then
        module:log(LOGLEVEL, "the party has not started yet")
        event.origin.send(st.error_reply(stanza, 'cancel', 'now-allowed'))
        return true

As you can see if the room’s owner is not joined the guest user can’t join the room, but instead of receiving the “Waiting for the host” popup message, the popup that you receive if the “internal_hashed” auth method is enabled, the lua module just call the now-allowed “method” (st.error_reply(stanza, ‘cancel’, ‘now-allowed’))

This method instructs jitsi to now allow the guest to join and just stop, instead of cycling every 5 seconds (with the original events.stanza) this make the guest invite unusable, because after the owner joins, the guest must reload the page to join the room, assuming he knows he’s entered

Looking at the conference.js code you can see two piece of code:

This is the one called from the custom lua module:

case JitsiConferenceErrors.NOT_ALLOWED_ERROR: {
            // let's show some auth not allowed page

This is the one called internally from prosody if the auth method is “internal_hashed”:

// not enough rights to create conference
        case JitsiConferenceErrors.AUTHENTICATION_REQUIRED: {

            const replaceParticipant = getReplaceParticipant(APP.store.getState());

            // Schedule reconnect to check if someone else created the room.
            this.reconnectTimeout = setTimeout(() => {
                room.join(null, replaceParticipant);
            }, 5000);

            const { password }
                = APP.store.getState()['features/base/conference'];

            AuthHandler.requireAuth(room, password);


As you can see the guest is receiving a login form to only use if he is the room owner or the instruction to just wait for him, then every 5 seconds jitsi automatically reload the room till the conference starts

I need to rebuild the same logic with the token auth method, i can’t find the same instruction to call the “wait for host” popup and automatically reload the room

it’s driving me crazy!

After commenting this line: org.jitsi.jicofo.auth.URL=XMPP:meet.example.com
and adding: org.jitsi.jicofo.auth.URL=EXT_JWT:meet.example.com

in file: /etc/jitsi/jicofo/sip-communicator.properties

and switching from event.origin.send(st.error_reply(stanza, ‘cancel’, ‘not-allowed’))
to event.origin.send(st.error_reply(stanza, ‘auth’, ‘not-authorized’))

on the mod_token_owner_party.lua the “wait for host” popup works correctly!

1 Like

Not working for me with the latest stable
I get “password required” message and it’s not waiting for the host

What installation types are you using ?

I’m on classic debian package

ii jicofo 1.0-756-1 all JItsi Meet COnference FOcus
ii jitsi-meet-prosody 1.0.5056-1 all Prosody configuration for Jitsi Meet
ii prosody 0.11.2-1+deb10u2 amd64 Lightweight Jabber/XMPP server

Debian 10 Buster
ii  prosody        0.11.2-1+deb10u2
ii  jicofo         1.0-756-1
ii  jitsi-meet            2.0.5963-1
ii  jitsi-meet-prosody    1.0.5056-1
ii  jitsi-meet-tokens     1.0.5056-1
ii  jitsi-meet-turnserver 1.0.5056-1
ii  jitsi-meet-web        1.0.5056-1
ii  jitsi-meet-web-config 1.0.5056-1
ii  jitsi-videobridge2    2.1-508-gb24f756c-1

Can you post your prosody conf ?

jitsi.mydomain.com.cfg.lua.txt (4.4 KB)

Looks like your conf is missing this piece:

VirtualHost "guest.jitsi.mydomain.com"
    authentication = "anonymous"
    c2s_require_encryption = false

Add it then restart prosody

AFAIK, the guest access is controled by allow_empty_token when the token authentication is active

BTW the same thing after added guest block

This is what I get

about the allow_empty_token i didn’t have it on my conf, can you try commenting it ?

the same result…

That’s strange, we’re using the same jitsi components version,

Just to be sure, here’s my conf files

jicofo-sip.communicator.properties.txt (212 Bytes)
meet.example.com.cfg.txt (4.4 KB)



I tested with the following line too


but this line seems problematic

Can you post your running mod_token_owner_party.lua file ?

local LOGLEVEL = "debug"
local TIMEOUT = module:get_option_number("party_check_timeout", 10)

local is_admin = require "core.usermanager".is_admin
local is_healthcheck_room = module:require "util".is_healthcheck_room
local it = require "util.iterators"
local st = require "util.stanza"
local timer = require "util.timer"
module:log(LOGLEVEL, "loaded")

local function _is_admin(jid)
    return is_admin(jid, module.host)

module:hook("muc-occupant-pre-join", function (event)
    local room, stanza = event.room, event.stanza
    local user_jid = stanza.attr.from

    if is_healthcheck_room(room.jid) or _is_admin(user_jid) then
        module:log(LOGLEVEL, "location check, %s", user_jid)

    -- if an owner joins, start the party
    local context_user = event.origin.jitsi_meet_context_user
    if context_user then
        if context_user["affiliation"] == "owner" or
           context_user["affiliation"] == "moderator" or
           context_user["affiliation"] == "teacher" then
            module:log(LOGLEVEL, "let the party begin")

    -- if the party has not started yet, don't accept the participant
    local occupant_count = it.count(room:each_occupant())
    if occupant_count < 2 then
        module:log(LOGLEVEL, "the party has not started yet")
        -- event.origin.send(st.error_reply(stanza, 'cancel', 'not-allowed'))
        event.origin.send(st.error_reply(stanza, 'auth', 'not-authorized'))
        return true

module:hook("muc-occupant-left", function (event)
    local room, occupant = event.room, event.occupant

    if is_healthcheck_room(room.jid) or _is_admin(occupant.jid) then

    -- no need to do anything for normal participant
    if room:get_affiliation(occupant.jid) ~= "owner" then
        module:log(LOGLEVEL, "a participant leaved, %s", occupant.jid)

    -- the owner is gone, start to check the room condition
        st.message({ type="groupchat", from=occupant.nick })
        :tag("body"):text("The owner is gone"))
    module:log(LOGLEVEL, "an owner leaved, %s", occupant.jid)

    -- check if there is any other owner here
    for _, o in room:each_occupant() do
        if not _is_admin(o.jid) then
            if room:get_affiliation(o.jid) == "owner" then
                module:log(LOGLEVEL, "an owner is here, %s", o.jid)

    -- since there is no other owner, kick all participants after TIMEOUT secs
    timer.add_task(TIMEOUT, function()
        if is_healthcheck_room(room.jid) then

        -- last check before kicking all participants
        -- if the owner is returned, cancel
        for _, o in room:each_occupant() do
            if not _is_admin(o.jid) then
                if room:get_affiliation(o.jid) == "owner" then
                    module:log(LOGLEVEL, "timer, an owner is here, %s", o.jid)

        -- kick all participants
        for _, p in room:each_occupant() do
            if not _is_admin(p.jid) then
                if room:get_affiliation(p.jid) ~= "owner" then
                    room:set_affiliation(true, p.jid, "outcast")
                    module:log(LOGLEVEL, "timer, kick the occupant, %s", p.jid)

        module:log(LOGLEVEL, "the party finished")

Sorry for the absence but I went on vacation, were you able to solve?

In the end, I converted the installation to docker, the configuration is a little different (meaning they converted a lot of options in the env file and once the configuration is generated, inside the .lua files under /root/.jitsi-meet-cfg) but everything works correctly: the JWT auth, the room destroy after the moderator leave, the guest waiting page…

You may need to enable guest domain in hosts section in config.js