Docker with JWT not working, depends on how you look at it

Hello all how are you?

I struggled with authenticating using JWT. so I reinstalled jitsi with docker.
now my client can connect also when the JWT is incorrect.

Please help
Thank you for your expertise.

.env file config:

ENABLE_AUTH=1
ENABLE_GUESTS=0
AUTH_TYPE=jwt
JWT_ALLOW_EMPTY=0
JWT_ENABLE_TOKEN_AUTH=1
JWT_APP_ID=my_app_id
JWT_APP_SECRET=my_app_secret 

generating

    def generate_options(self, room: str, name: str, avatar_link: str):
        assert room
        return {
            'domain': self.app_domain,
            'options': {
                'roomName': room,
                'noSSL': not self.mode_production,
                'userInfo': {
                    'displayName': name
                },
                'width': '100%',
                'height': '100%',
                'jwt': self._generate_token(room, name, avatar_link)
            }
        }

    def _generate_token(self, room: str, name: str, avatar_link: str):
        msg = {
            "context": {
                "user": {
                    "avatar": avatar_link,
                    "name": name,
                }
            },
            "aud": self.app_id,
            "iss": self.app_id,
            "sub": self.app_domain,
            "room": room,
            "exp": (datetime.utcnow() + timedelta(hours=1)).timestamp()
        }
        return jwt.encode(msg, 'yada yada incorrect secret', algorithm='HS256').decode("utf-8")

any help pleas pelase

I see exactly the same thing. It’s as though authentication isn’t enabled at all. Have you learned anything more about this or reported it as a GitHub issue?

(I don’t know what your second code snippet is about. I’m not familiar with any of that. I simply followed the instructions to enable JWT auth.)

hi @Shotster not resolved yet. do you have any idea?

The code snippet is the way I am creating the JWT token with python

Thank you for the comment

No, but I did submit a GitHub issue.

What happens when you access a room without using any token at all?

Oh, ok. I just used the sample JSON provided in the documentation and manually generated the JWT via jwt.io. As I noted, though, users can enter a room without even using a token. Maybe I’m overlooking something obvious. :confused:

+1 the issue. hope it will resolve soon

1 Like

@shay_te I can’t find JWT_ENABLE_TOKEN_AUTH=1 env variable in .env file?

Below is my config for JWT

# Enable authentication
ENABLE_AUTH=1

# Enable guest access
#ENABLE_GUESTS=1

# Select authentication type: internal, jwt or ldap
AUTH_TYPE=jwt

# JWT authentication
#

# Application identifier
JWT_APP_ID=E1B40

# Application secret known only to your token
JWT_APP_SECRET=Set_your_secret

# (Optional) Set asap_accepted_issuers as a comma separated list
JWT_ACCEPTED_ISSUERS=my_web_client,my_app_client

# (Optional) Set asap_accepted_audiences as a comma separated list
JWT_ACCEPTED_AUDIENCES=myserver1,myserver2

JWT_ALLOW_EMPTY=0
JWT_TOKEN_AUTH_MODULE=token_verification

@Shotster I went through your logs in github repo and I can’t see couple of things in the logs

  1. no websocket enabled
  2. no token_verification module loaded

It would be great if you can share prosody logs with LOG_LEVEL=debug in prosody config.
Also please share jitsi-meet.cfg.lua file from ~/.jitsi-meet-cfg/prosody directory. It’ll help me to identify whether config related to JWT loaded or not.

UPDATE
sorry, websocket for prosody enabled in master branch not in stable-5142.

Can you show your “jitsi-meet.cfg.lua” file in .“jitsi-meet-cfg/prosody/configi/conf.d”?

WebSockets are enabled by default in latest docker. I can see the WS in the Chrome dev console.

Where exactly is the log stored within the container? There’s nothing in var/log/prosody.

Here t is…

admins = {
    "focus@auth.meet.jitsi",
    "jvb@auth.meet.jitsi"
}

plugin_paths = { "/prosody-plugins/", "/prosody-plugins-custom" }
http_default_host = "meet.jitsi"














VirtualHost "meet.jitsi"

    authentication = "anonymous"

    ssl = {
        key = "/config/certs/meet.jitsi.key";
        certificate = "/config/certs/meet.jitsi.crt";
    }
    modules_enabled = {
        "bosh";
        "pubsub";
        "ping";
        "speakerstats";
        "conference_duration";
        
        
        
    }

    

    speakerstats_component = "speakerstats.meet.jitsi"
    conference_duration_component = "conferenceduration.meet.jitsi"

    c2s_require_encryption = false



VirtualHost "auth.meet.jitsi"
    ssl = {
        key = "/config/certs/auth.meet.jitsi.key";
        certificate = "/config/certs/auth.meet.jitsi.crt";
    }
    authentication = "internal_hashed"


VirtualHost "recorder.meet.jitsi"
    modules_enabled = {
      "ping";
    }
    authentication = "internal_hashed"


Component "internal-muc.meet.jitsi" "muc"
    storage = "memory"
    modules_enabled = {
        "ping";
        
    }
    muc_room_locking = false
    muc_room_default_public_jids = true

Component "muc.meet.jitsi" "muc"
    storage = "memory"
    modules_enabled = {
        "muc_meeting_id";
        
        
    }
    muc_room_cache_size = 1000
    muc_room_locking = false
    muc_room_default_public_jids = true

Component "focus.meet.jitsi"
    component_secret = "7960b59ee8a1d40c0be645cd7097363c"

Component "speakerstats.meet.jitsi" "speakerstats_component"
    muc_component = "muc.meet.jitsi"

Component "conferenceduration.meet.jitsi" "conference_duration_component"
    muc_component = "muc.meet.jitsi"

To get the prosody container name, use docker ps -a command . Use docker logs prosody_container_name 2>&1 | grep "token" command

Thanks, but I’ve already tried that command as suggested in this issue comment. Nothing is output. The prompt just reappears. What’s supposed to happen? Is it writing to a file, or should the log contents be printed to the console?

Your jitsi-meet.cfg.lua file is missing config for jwt

Component "{{ .Env.XMPP_MUC_DOMAIN }}" "muc"
    storage = "memory"
    modules_enabled = {
        "muc_meeting_id";
        {{ if .Env.XMPP_MUC_MODULES }}
        "{{ join "\";\n\"" (splitList "," .Env.XMPP_MUC_MODULES) }}";
        {{ end }}
        {{ if and $ENABLE_AUTH (eq $AUTH_TYPE "jwt") }}
        "{{ join "\";\n\"" (splitList "," .Env.JWT_TOKEN_AUTH_MODULE) }}";
        --"token_affiliation";
        --"token_moderation";
        {{ end }}
        {{ if .Env.ENABLE_RECORDING }}
        "allow_jibri_tobypass";
        {{ end }}
        {{ if eq $ENABLE_SUBDOMAINS "true" }}
        "muc_domain_mapper";
        {{ end }}
    }

In above config If ENABLE_AUTH=1 and AUTH_TYPE=jwt then it will add module token_verification but it is not present in your config hence you are not getting anything when running grep command. Value of JWT_TOKEN_AUTH_MODULE is set to token_verification by default even if you are not configuring it.

try enabling AUTH_TYPE=jwt and ENABLE_AUTH=1 in docker-compose.yml file under service prosody environment

Below is my default jitsi-meet.cfg.lua file. You can use it but you have to build your own docker image then. This enables websocket for prosody too. This requires some additional config at web level. you can clone docker-jitsi-meet master repo and try creating your own docker images.

admins = {
    "{{ .Env.JICOFO_AUTH_USER }}@{{ .Env.XMPP_AUTH_DOMAIN }}",
    "{{ .Env.JVB_AUTH_USER }}@{{ .Env.XMPP_AUTH_DOMAIN }}"
}

plugin_paths = { "/prosody-plugins/", "/prosody-plugins-custom" }
http_default_host = "{{ .Env.XMPP_DOMAIN }}"

{{ $ENABLE_AUTH := .Env.ENABLE_AUTH | default "0" | toBool }}
{{ $ENABLE_GUEST_DOMAIN := and $ENABLE_AUTH (.Env.ENABLE_GUESTS | default "0" | toBool)}}
{{ $AUTH_TYPE := .Env.AUTH_TYPE | default "internal" }}
{{ $JWT_ASAP_KEYSERVER := .Env.JWT_ASAP_KEYSERVER | default "" }}
{{ $JWT_ALLOW_EMPTY := .Env.JWT_ALLOW_EMPTY | default "0" | toBool }}
{{ $JWT_AUTH_TYPE := .Env.JWT_AUTH_TYPE | default "token" }}
{{ $JWT_TOKEN_AUTH_MODULE := .Env.JWT_TOKEN_AUTH_MODULE | default "token_verification" }}
{{ $ENABLE_LOBBY := .Env.ENABLE_LOBBY | default "0" | toBool }}
{{ $ENABLE_XMPP_WEBSOCKET := .Env.ENABLE_XMPP_WEBSOCKET | default "1" | toBool }}
{{ $PUBLIC_URL := .Env.PUBLIC_URL | default "https://localhost:8443" -}}

{{ if and $ENABLE_AUTH (eq $AUTH_TYPE "jwt") .Env.JWT_ACCEPTED_ISSUERS }}
asap_accepted_issuers = { "{{ join "\",\"" (splitList "," .Env.JWT_ACCEPTED_ISSUERS) }}" }
{{ end }}

{{ if and $ENABLE_AUTH (eq $AUTH_TYPE "jwt") .Env.JWT_ACCEPTED_AUDIENCES }}
asap_accepted_audiences = { "{{ join "\",\"" (splitList "," .Env.JWT_ACCEPTED_AUDIENCES) }}" }
{{ end }}

{{ if $ENABLE_XMPP_WEBSOCKET }}
-- Deprecated in 0.12
-- https://github.com/bjc/prosody/commit/26542811eafd9c708a130272d7b7de77b92712de
cross_domain_websocket = { "{{ $PUBLIC_URL }}" };
consider_bosh_secure = true;
{{ end }}

VirtualHost "{{ .Env.XMPP_DOMAIN }}"
{{ if $ENABLE_AUTH }}
  {{ if eq $AUTH_TYPE "jwt" }}
    authentication = "{{ $JWT_AUTH_TYPE }}"
    app_id = "{{ .Env.JWT_APP_ID }}"
    app_secret = "{{ .Env.JWT_APP_SECRET }}"
    allow_empty_token = {{ if $JWT_ALLOW_EMPTY }}true{{ else }}false{{ end }}
    {{ if $JWT_ASAP_KEYSERVER }}
    asap_key_server = "{{ .Env.JWT_ASAP_KEYSERVER }}"
    {{ end }}

    {{ else if eq $AUTH_TYPE "ldap" }}
    authentication = "cyrus"
    cyrus_application_name = "xmpp"
    allow_unencrypted_plain_auth = true
  {{ else if eq $AUTH_TYPE "internal" }}
    authentication = "internal_hashed"
  {{ end }}
{{ else }}
    -- https://github.com/jitsi/docker-jitsi-meet/pull/502#issuecomment-619146339
    {{ if $ENABLE_XMPP_WEBSOCKET }}
    authentication = "token"
    {{ else }}
    authentication = "anonymous"
    {{ end }}
    app_id = ""
    app_secret = ""
    allow_empty_token = true
{{ end }}
    ssl = {
        key = "/config/certs/{{ .Env.XMPP_DOMAIN }}.key";
        certificate = "/config/certs/{{ .Env.XMPP_DOMAIN }}.crt";
    }
    modules_enabled = {
        {{ if $ENABLE_XMPP_WEBSOCKET }}
        "websocket";
        "smacks"; -- XEP-0198: Stream Management
        {{ end }}
        "bosh";
        "pubsub";
        "ping";
        "speakerstats";
        "conference_duration";
        {{ if and $ENABLE_LOBBY (not $ENABLE_GUEST_DOMAIN) }}
        "muc_lobby_rooms";
        {{ end }}
        {{ if .Env.XMPP_MODULES }}
        "{{ join "\";\n\"" (splitList "," .Env.XMPP_MODULES) }}";
        {{ end }}
        {{ if and $ENABLE_AUTH (eq $AUTH_TYPE "ldap") }}
        "auth_cyrus";
        {{end}}
        {{ if .Env.ENABLE_RECORDING }}
        "allow_jibri_tobypass";
        {{ end }}
    }

    {{ if and $ENABLE_LOBBY (not $ENABLE_GUEST_DOMAIN) }}
    main_muc = "{{ .Env.XMPP_MUC_DOMAIN }}"
    lobby_muc = "lobby.{{ .Env.XMPP_DOMAIN }}"
    {{ if .Env.XMPP_RECORDER_DOMAIN }}
    muc_lobby_whitelist = { "{{ .Env.XMPP_RECORDER_DOMAIN }}" }
    {{ end }}
    {{ end }}

    speakerstats_component = "speakerstats.{{ .Env.XMPP_DOMAIN }}"
    conference_duration_component = "conferenceduration.{{ .Env.XMPP_DOMAIN }}"

    c2s_require_encryption = false

{{ if $ENABLE_GUEST_DOMAIN }}
VirtualHost "{{ .Env.XMPP_GUEST_DOMAIN }}"
    -- https://github.com/jitsi/docker-jitsi-meet/pull/502#issuecomment-619146339
    {{ if $ENABLE_XMPP_WEBSOCKET }}
    authentication = "token"
    {{ else }}
    authentication = "anonymous"
    {{ end }}
    app_id = ""
    app_secret = ""
    allow_empty_token = true

    c2s_require_encryption = false

    {{ if $ENABLE_LOBBY }}
    modules_enabled = {
        "muc_lobby_rooms";
    }

    main_muc = "{{ .Env.XMPP_MUC_DOMAIN }}"
    lobby_muc = "lobby.{{ .Env.XMPP_DOMAIN }}"
    {{ if .Env.XMPP_RECORDER_DOMAIN }}
    muc_lobby_whitelist = { "{{ .Env.XMPP_RECORDER_DOMAIN }}" }
    {{ end }}
    {{ end }}

{{ end }}

VirtualHost "{{ .Env.XMPP_AUTH_DOMAIN }}"
    ssl = {
        key = "/config/certs/{{ .Env.XMPP_AUTH_DOMAIN }}.key";
        certificate = "/config/certs/{{ .Env.XMPP_AUTH_DOMAIN }}.crt";
    }
    authentication = "internal_hashed"

{{ if .Env.XMPP_RECORDER_DOMAIN }}
VirtualHost "{{ .Env.XMPP_RECORDER_DOMAIN }}"
    modules_enabled = {
      "ping";
    }
    authentication = "internal_hashed"
{{ end }}

Component "{{ .Env.XMPP_INTERNAL_MUC_DOMAIN }}" "muc"
    storage = "memory"
    modules_enabled = {
        "ping";
        {{ if .Env.XMPP_INTERNAL_MUC_MODULES }}
        "{{ join "\";\n\"" (splitList "," .Env.XMPP_INTERNAL_MUC_MODULES) }}";
        {{ end }}
    }
    muc_room_locking = false
    muc_room_default_public_jids = true

Component "{{ .Env.XMPP_MUC_DOMAIN }}" "muc"
    storage = "memory"
    modules_enabled = {
        "muc_meeting_id";
        {{ if .Env.XMPP_MUC_MODULES }}
        "{{ join "\";\n\"" (splitList "," .Env.XMPP_MUC_MODULES) }}";
        {{ end }}
        {{ if and $ENABLE_AUTH (eq $AUTH_TYPE "jwt") }}
        "{{ join "\";\n\"" (splitList "," .Env.JWT_TOKEN_AUTH_MODULE) }}";
        {{ end }}
        {{ if .Env.ENABLE_RECORDING }}
        "allow_jibri_tobypass";
        {{ end }}
    }
    muc_room_cache_size = 1000
    muc_room_locking = false
    muc_room_default_public_jids = true

Component "focus.{{ .Env.XMPP_DOMAIN }}"
    component_secret = "{{ .Env.JICOFO_COMPONENT_SECRET }}"

Component "speakerstats.{{ .Env.XMPP_DOMAIN }}" "speakerstats_component"
    muc_component = "{{ .Env.XMPP_MUC_DOMAIN }}"

Component "conferenceduration.{{ .Env.XMPP_DOMAIN }}" "conference_duration_component"
    muc_component = "{{ .Env.XMPP_MUC_DOMAIN }}"

{{ if $ENABLE_LOBBY }}
Component "lobby.{{ .Env.XMPP_DOMAIN }}" "muc"
    storage = "memory"
    restrict_room_creation = true
    muc_room_locking = false
    muc_room_default_public_jids = true
{{ end }}

I can already see that those env vars are set, but I went ahead and changed them in docker-compose.yml file, and it made no difference.

There must be something simple I’m overlooking. As I said, though, this is a fresh docker jitsi install. The only change I made was to replace the TLS certs with my own so that I could access the site over https.

@Shotster what about this?

Ok, I rebuilt the prosody container, and JWT is now working. A valid JWT is now required before a user enters the room. Otherwise, an auth failed message appears.

What I don’t understand is how guest access is supposed to work. What I want is for anyone with a valid token to be able to create a room and become the moderator. However, a token should not be required for guests to access the room. Is that possible?

Try ENABLE_GUEST=1

Of course, I tried that. When a guest visits an existing room, Jitsi just says they’re the only one in it, and they can’t see the moderator who created it or vice versa.

I was expecting it to work in basically the same way as a secure domain, but it doesn’t. :confused:

EDIT

Here’s my .env

# Enable authentication
ENABLE_AUTH=1

# Enable guest access
ENABLE_GUESTS=1

# Select authentication type: internal, jwt or ldap
AUTH_TYPE=jwt

# JWT authentication
#

# Application identifier
JWT_APP_ID=my_jitsi_app_id

# Application secret known only to your token
JWT_APP_SECRET=xxxxx

# Allow anonymous users with no JWT while validating JWTs when provided
JWT_ALLOW_EMPTY=1

I’ve also tried enabling and disabling JWT_ALLOW_EMPTY, but it doesn’t seem to make a difference.

ohk. Can you chekc below part in jitsi-meet.cfg.lua file?

{{ if $ENABLE_GUEST_DOMAIN }}
VirtualHost "{{ .Env.XMPP_GUEST_DOMAIN }}"
    -- https://github.com/jitsi/docker-jitsi-meet/pull/502#issuecomment-619146339
    {{ if $ENABLE_XMPP_WEBSOCKET }}
    authentication = "token"
    {{ else }}
    authentication = "anonymous"
    {{ end }}
    app_id = ""
    app_secret = ""
    allow_empty_token = true

    c2s_require_encryption = false

    {{ if $ENABLE_LOBBY }}
    modules_enabled = {
        "muc_lobby_rooms";
    }

This is what mine and the latest stable looks like…

{{ if $ENABLE_GUEST_DOMAIN }}
VirtualHost "{{ .Env.XMPP_GUEST_DOMAIN }}"
    authentication = "anonymous"
    c2s_require_encryption = false

    {{ if $ENABLE_LOBBY }}
    modules_enabled = {
        "muc_lobby_rooms";
    }

Is the latest stable not the latest? I’m confused about which version I should be using.