Setting up authentication on a jitsi server

This was last covered several years ago in Jitsi-meet: how to enable authentication?, however the solution there is incomplete and no longer seems to work.

Can anyone help me figure out how to set up authentication on a jitsi server with Nixpkgs 21.11? I want to require authenticated users to create a channel, but anonymous users are allowed to join it.

I’ve gotten to a state where I can get my jitsi server to prompt me for a password, but it never recognizes my as a host. Further, I can find no errors in the prosody, videobridge, or jicofo log files. My configuration currently looks like this (jitsi_fqdn = jitsi.luminescent-dreams.com)

    services.jitsi-meet = {
      enable = true;
      hostName = jitsi_fqdn;
      config = {
        authdomain = jitsi_fqdn;
        enableInsecureRoomNameWarning = true;
        fileRecordingsEnabled = false;
        liveStreamingEnabled = false;
        prejoinPageEnabled = true;
        hosts = {
          domain = jitsi_fqdn;
          anonymousDomain = "guests.${jitsi_fqdn}";
        };
      };
    };

    services.jitsi-videobridge = {
      enable = true;
      openFirewall = true;
    };

    services.coturn = {
      enable = true;
      ...
    };

    services.prosody = {
      allowRegistration = true;
      virtualHosts = {
        "${jitsi_fqdn}" = {
          enabled = true;
          domain = "${jitsi_fqdn}";
          extraConfig = ''
            authentication = "internal_hashed"
            '';
        };

        "guests.${jitsi_fqdn}" = {
          domain = "guests.${jitsi_fqdn}";
          enabled = true;
          extraConfig = ''
            authentication = "anonymous"
            c2s_require_encryption = false
            '';
        };
      };
    };

    services.jicofo = {
      enable = true;
      config = {
        "org.jitsi.jicofo.auth.URL" = "XMPP:${jitsi_fqdn}";
      };
    };

This is the closest I’m getting to an error message at this point:

107881   │ Feb 07 06:29:47 matrix prosody[477020]: mod_bosh: Handling new request table: 0x2aed970: <body rid="1767851451" sid="0d7e27ad-9be8-4e34-8762-75badfe9ca86" xmlns="http://jabber.org/protocol/httpbind"><i
        │ q id="f848a3e4-2efa-42a4-8d25-c9370ec2fc8b:sendIQ" to="focus.jitsi.luminescent-dreams.com" type="set" xmlns="jabber:client"><conference machine-uid="dd94d2ad2b2bfc14c63ebee2a635762b" room="the-forgotte
        │ n-city@conference.jitsi.luminescent-dreams.com" xmlns="http://jitsi.org/protocol/focus"><property name="disableRtx" value="false"/></conference></iq></body>
107882   │                                         ----------
107883   │ Feb 07 06:29:47 matrix prosody[477020]: mod_bosh: BOSH body open (sid: 0d7e27ad-9be8-4e34-8762-75badfe9ca86)
107884   │ Feb 07 06:29:47 matrix prosody[477020]: bosh0d7e27ad-9be8-4e34-8762-75badfe9ca86: rid: 1767851451, sess: 1767851450, diff: 1
107885   │ Feb 07 06:29:47 matrix prosody[477020]: mod_bosh: BOSH stanza received: <iq id='f848a3e4-2efa-42a4-8d25-c9370ec2fc8b:sendIQ' to='focus.jitsi.luminescent-dreams.com' type='set'>
107886   │ Feb 07 06:29:47 matrix prosody[477020]: bosh0d7e27ad-9be8-4e34-8762-75badfe9ca86: Received[c2s]: <iq id='f848a3e4-2efa-42a4-8d25-c9370ec2fc8b:sendIQ' to='focus.jitsi.luminescent-dreams.com' type='set'>
107887   │ Feb 07 06:29:47 matrix prosody[477020]: focus.jitsi.luminescent-dreams.com:client_proxy: received stanza from c2s session
107888   │ Feb 07 06:29:47 matrix prosody[477020]: focus.jitsi.luminescent-dreams.com:client_proxy: stanza to target: name = iq, type = set
107889   │ Feb 07 06:29:47 matrix prosody[477020]: focus.jitsi.luminescent-dreams.com:client_proxy: NAT-ed stanza: from: savanni@jitsi.luminescent-dreams.com/RvPQmZVk -> focus.jitsi.luminescent-dreams.com/savanni
        │ @jitsi.luminescent-dreams.com/RvPQmZVk, to: focus.jitsi.luminescent-dreams.com -> focus@auth.jitsi.luminescent-dreams.com/focus
107890   │ Feb 07 06:29:47 matrix prosody[477020]: c2s28f4e00: Sending[c2s]: <iq id='f848a3e4-2efa-42a4-8d25-c9370ec2fc8b:sendIQ' to='focus@auth.jitsi.luminescent-dreams.com/focus' type='set' from='focus.jitsi.lu
        │ minescent-dreams.com/savanni@jitsi.luminescent-dreams.com/RvPQmZVk'>
107891   │ Feb 07 06:29:47 matrix prosody[477020]: mod_bosh: Session 0d7e27ad-9be8-4e34-8762-75badfe9ca86 has 2 out of 1 requests open
107892   │ Feb 07 06:29:47 matrix prosody[477020]: mod_bosh: and there are 0 things in the send_buffer:
107893   │ Feb 07 06:29:47 matrix prosody[477020]: mod_bosh: We are holding too many requests, so...
107894   │ Feb 07 06:29:47 matrix prosody[477020]: mod_bosh: ...sending an empty response
107895   │ Feb 07 06:29:47 matrix prosody[477020]: mod_bosh: We have an open request, so sending on that
107896   │ Feb 07 06:29:47 matrix prosody[477020]: mod_bosh: Request destroyed: table: 0x235da10
107897   │ Feb 07 06:29:47 matrix prosody[477020]: socket: try to close client connection with id: 2a5dc80
107898   │ Feb 07 06:29:47 matrix prosody[477020]: socket: closing delayed until writebuffer is empty
107899   │ Feb 07 06:29:47 matrix prosody[477020]: mod_bosh: Have nothing to say, so leaving request unanswered for now
107900   │ Feb 07 06:29:47 matrix prosody[477020]: socket: closing client after writing
107901   │ Feb 07 06:29:47 matrix prosody[477020]: socket: closing client with id: 2a5dc80 client to close
107902   │ Feb 07 06:29:47 matrix prosody[477020]: c2s28f4e00: Received[c2s]: <iq id='f848a3e4-2efa-42a4-8d25-c9370ec2fc8b:sendIQ' to='focus.jitsi.luminescent-dreams.com/savanni@jitsi.luminescent-dreams.com/RvPQm
        │ ZVk' type='error'>
107903   │ Feb 07 06:29:47 matrix prosody[477020]: focus.jitsi.luminescent-dreams.com:client_proxy: received stanza from c2s session
107904   │ Feb 07 06:29:47 matrix prosody[477020]: focus.jitsi.luminescent-dreams.com:client_proxy: non-presence stanza from target: name = iq, type = error
107905   │ Feb 07 06:29:47 matrix prosody[477020]: focus.jitsi.luminescent-dreams.com:client_proxy: de-NAT-ed stanza: from: focus@auth.jitsi.luminescent-dreams.com/focus -> focus.jitsi.luminescent-dreams.com, to:
        │  focus.jitsi.luminescent-dreams.com/savanni@jitsi.luminescent-dreams.com/RvPQmZVk -> savanni@jitsi.luminescent-dreams.com/RvPQmZVk
107906   │ Feb 07 06:29:47 matrix prosody[477020]: mod_bosh: We have an open request, so sending on that
107907   │ Feb 07 06:29:47 matrix prosody[477020]: mod_bosh: Request destroyed: table: 0x2aedc50
107908   │ Feb 07 06:29:47 matrix prosody[477020]: bosh0d7e27ad-9be8-4e34-8762-75badfe9ca86: BOSH session marked as inactive (for 60s)
107909   │ Feb 07 06:29:47 matrix prosody[477020]: socket: try to close client connection with id: 298da50
107910   │ Feb 07 06:29:47 matrix prosody[477020]: socket: closing delayed until writebuffer is empty
107911   │ Feb 07 06:29:47 matrix prosody[477020]: socket: closing client after writing
107912   │ Feb 07 06:29:47 matrix prosody[477020]: socket: closing client with id: 298da50 client to close
107913   │ Feb 07 06:29:48 matrix prosody[477020]: socket: accepted incoming client connection from: 127.0.0.1 40764 to 5280
107914   │ Feb 07 06:29:48 matrix prosody[477020]: http.server: Firing event: POST /http-bind
107915   │ Feb 07 06:29:48 matrix prosody[477020]: mod_bosh: Handling new request table: 0x2aaddb0: <body rid="1767851452" sid="0d7e27ad-9be8-4e34-8762-75badfe9ca86" xmlns="http://jabber.org/protocol/httpbind"/>
107916   │                                         ----------
107917   │ Feb 07 06:29:48 matrix prosody[477020]: mod_bosh: BOSH body open (sid: 0d7e27ad-9be8-4e34-8762-75badfe9ca86)
107918   │ Feb 07 06:29:48 matrix prosody[477020]: bosh0d7e27ad-9be8-4e34-8762-75badfe9ca86: rid: 1767851452, sess: 1767851451, diff: 1
107919   │ Feb 07 06:29:48 matrix prosody[477020]: mod_bosh: Session 0d7e27ad-9be8-4e34-8762-75badfe9ca86 has 1 out of 1 requests open
107920   │ Feb 07 06:29:48 matrix prosody[477020]: mod_bosh: and there are 0 things in the send_buffer:
107921   │ Feb 07 06:29:48 matrix prosody[477020]: mod_bosh: Have nothing to say, so leaving request unanswered for now

But this is only a fragment of the printouts that appear to occur on every auth attempt. I see at least a hundred such lines, again with no obvious error.

1 Like

Additional information, these are my exact closure names:

yp6ldhzv3v1rblxjd1c79l6gdj0gch74-prosody-0.11.10
57cn6rv9sl35s3gg5n0zvs9gv49ynclc-jicofo-1.0-798
9fca3g9szvbdfdkid6x1r2gyvl6ddyci-jitsi-videobridge2-2.1-551-g2ad6eb0b

I suspect that package development for Jitsi-Meet hasn’t matured. It’ll allow a quick basic setup of Jitsi-Meet, but the service options to modify the sub-services (e.g. posody, jicofo) seems to be missing.

Per the Jitsi docs [1] for a non-NixOS setup of authentication for Jitsi where only authorized users can create rooms and guests can join, as you specified.

[1]: Secure Domain setup | Jitsi Meet

The four major steps mentioned there:

  1. Configure prosody for guests and auth users.
  2. Add guest domain to Jitsi frontend (not nginx).
  3. Configure jicofo to only accept conference allocation requests from authenticated domain.
  4. Create users in prosody.

So here’s what I would troubleshoot…

1 Configure prosody for guests and auth users

For non-NixOS, this is needed in /etc/prosody/conf.d/$(hostname -f).cfg.lua

VirtualHost "jitsi.luminescent-dreams.com"
  authentication = "internal_hashed"

VirtualHost "guests.luminescent-dreams.com"
  authentication = "anonymous"
  c2s_require_encryption = false

You seem to attempt this in your config for services.prosody. It seems you expect your manual prosody config to merge with the jitsi-meet automatic prosody config. I’m not certain that happens (it could, I just don’t know).

I recommend reviewing the prosody config file generated by NixOS and verify the meet.luminescent-dreams.com virtual host has authentication = "internal_hashed".

I found mine with cat /etc/systemd/system/prosody.service | grep "X-Restart-Triggers" | sed 's/X-Restart-Triggers=//' | xargs cat

2 Add guest domain to Jitsi frontend (not nginx)

var config = {
  // ...
  hosts: {
    domain: 'meet.luminescent-dreams.com',
    anonymousdomain: 'guests.meet.luminescent-dreams.com',
  },
}

Note the lowercase ‘d’ in anonymousdomain. You used anonymousDomain, but the jitsi-meet module doesn’t explicitly employ any mechanism to convert the Nix camelcase convention into that used by Jitsi.

3 Configure jicofo to only accept conference allocation requests from authenticated domain

Supposed to update /etc/jitsi/jicofo/sip-communicator.properties with…

org.jitsi.jicofo.auth.URL=XMPP:meet.luminescent-dreams.com

And possibly have this in /etc/jitsi/jicofo/jicofo.conf

jicofo {
  authentication: {
    enabled: true
    type: XMPP
    login-url: meet.luminescent-dreams.com
 }
 ...

You accomplish the first per the NixOS options for services.jicofo.config.

I don’t know if the second is required. Maybe the jicofo module needs an update to support this? I’d save this this as a last resort.

4 Create users in prosody

Run something akin to prosodyctl register <username> meet.luminescent-dreams.com <password> for each user you want to add to your system. Looks like an admin has to choose passwords for users instead of letting users set a private password.

Conclusion

I’d start with anonymousdomain first, then verify the prosody config file, then register a user if you haven’t already.
Finally, restart services (prosody, jicofo, jitsi-videobridge2).

I’ve yet to find time to upgrade my jitsi server to use authentication, so this write-up is my exercise in learning the process now for when I have time to implement later.

Hope this helps.

2 Likes

Potentially, yes. I hadn’t noticed the capitalization issue. I think I’ve compared my work to what you posted here and everything was the same.

However I also think that there’s a formatting issue. When I look at the prosody config file, I see lines related to all of this that aren’t indented in the areas where they should be. I haven’t had time to manually fix the configuration file to test that theory, yet.

No luck.

Or some luck. Something like that.

I corrected the spelling error, went over everything very carefully, and now when I try to log in, it gets stuck with the message “obtaining session-id”. And then I get this error message in the console:

2022-02-18T01:48:11.582Z [features/authentication] <h/</<>:  authenticateAndUpgradeRole failed 
Object { authenticationError: "not-authorized", message: "not authorized user domain" }
​
authenticationError: "not-authorized"
​
message: "not authorized user domain"

But, at the same time, I am able to log in to the prosody server with that username and password. So something at least is working.

I think maybe my next step will be to fix the prosody module. I’ve figured out that the extraConfig stanzas that I put above, which are supposed to be associated with a virtualHost, are actually being put at the very end of the prosody config file. So, no telling how prosody is interpreting that.

2 Likes

I found a post [1] related to this particular authentication error on jitsi’s forum.

Unfortunately, the final solution there was to drop a “bare-metal” install on Ubuntu in favor of a Jitsi docker container. Still, if the docker container works, then it can provide a source of working configs to compare against.

From the “help” given in the thread, it seems like authentication is difficult to set up. And there may be outstanding bugs, according to this comment [2], that are fixed in the docker image released by Jitsi. And the fix appears to be using the jicofo.conf I mentioned previously…

And issue posted for nixpkgs [3] suggests auth won’t work without jicofo.conf as new keys added to jicofo.conf cannot be set in sip-communicator.properties. Possible workaround provided by betaboon.

[1]: Authentication isn't working! - Install & Config - Jitsi Community Forum - developers & users
[2]: Authentication isn't working! - #10 by Anton_Karlan - Install & Config - Jitsi Community Forum - developers & users
[3]: jitsi-meet / jicofo uses old config file sip-communicator.properties (breaks secure domain auth) · Issue #141641 · NixOS/nixpkgs · GitHub

1 Like

I took a big leap of faith on this one and I got it working (I’m relatively new with nixos).

Here’s the relevant part of the configuration. Beware of allow_empty_token: for my use case, I want guests from outside of the domain to access already created rooms (they need to know the room name). It doesn’t allow them to create a new room.

    services.prosody = {
      # First, the "token" authentication for jitsi requires us to add some packages to the prosody lua environment.
      package = pkgs.prosody.override {
        withExtraLuaPackages = p:
          with p; [
            cjson
            basexx
            luaossl
            inspect
          ];
      };
      # Then we can activate token verification.
      extraModules = ["token_verification"];
      # This instructs our instance to require a JWT token to access.
      virtualHosts = {
        "jitsi.${domain}" = {
          extraConfig = ''
              app_id="jitsi"
              app_secret="changeme"
              allow_empty_token = true
          '';
        };
      };
    };
    services.jitsi-meet = {
      secureDomain = {
        enable = true;
        authentication = "token";
      };
      extraConfig = ''
        config.hosts.anonymousdomain = 'guest.jitsi.${domain}';
      '';
    };

It took me quite some effort to figure out how to override the lua environment, but I think I understand nixpkgs a lot more now!

Additionally, I patched GitHub - nordeck/jitsi-keycloak-adapter: Allow Jitsi to use Keycloak as an identity and OIDC provider. SSO support for Jitsi into the jitsi-meet package. I’m not very proud of this solution: I added the relevant files to my repository, overlayed jitsi-meet, and spin up a systemd service. It ended up looking like this:

Overlay:

prev: final: let
  jitsi-oidc-adapter = ../jitsi-oidc-adapter-repo;
in {
  jitsi-meet = final.jitsi-meet.overrideAttrs (old: {
    installPhase =
      (old.installPhase or "")
      + ''
        mkdir -p $out/oidc-adapter
        cp -r ${jitsi-oidc-adapter}/*.ts $out/oidc-adapter/
        cp -r ${jitsi-oidc-adapter}/jitsi-meet/* $out/
      '';
  });
}

Module:

{pkgs, ...}:
let
  inherit (import ../constants.nix) domain;
in
{
  users.users.jitsi-oidc-adapter = {
    isSystemUser = true;
    group = "jitsi-oidc-adapter";
  };
  users.groups.jitsi-oidc-adapter = {};
  systemd.services.jitsi-oidc-adapter = {
    enable = true;
    wantedBy = ["multi-user.target"];
    serviceConfig = {
      Type = "exec";
      User = "jitsi-oidc-adapter";
      Environment = [
        "XDG_CACHE_HOME=/tmp/deno"
        "KEYCLOAK_ORIGIN=https://auth.${domain}"
        "KEYCLOAK_REALM=master"
        "KEYCLOAK_CLIENT_ID=jitsi"
        # These must be the same ones configured in the main VirtualDomain
        "JWT_APP_ID=jitsi"
        "JWT_APP_SECRET=changeme"
        "JWT_EXP_SECOND=3600"
      ];
      ExecStart = "${pkgs.deno}/bin/deno run --allow-net --allow-env ${pkgs.jitsi-meet}/oidc-adapter/adapter.ts";
    };
  };

  services.nginx.virtualHosts."jitsi.${domain}".locations = {
    "/oidc/redirect".proxyPass = "http://127.0.0.1:9000";
    "/oidc/tokenize".proxyPass = "http://127.0.0.1:9000";
    "/oidc/auth".proxyPass = "http://127.0.0.1:9000";
    "@root_path" = {
      extraConfig = ''
        if ($arg_oidc) {
            rewrite ^/(.*)$ / break;
        }
        if ($arg_jwt) {
            rewrite ^/(.*)$ / break;
        }
        rewrite ^/(.*)$ /static/oidc-redirect.html;
      '';
    };
  };
}

I hope this is useful!

5 Likes

Kudos for this. Does this mean your jitsi install is now complete (all standard features) and secure (at least authenticated access and https) using entirely nix-modules?

About 2 years ago I tried and it was an utter disaster (I could only setup a really basic test installation with it, but nothing production-ready), so I made a simple docker-compose wrapper service instead and crafted a compose file.

Have the NixOS jitsi modules significantly improved lately?

As a bonus: have you ever gotten whiteboard to work? (For me it would crash on more than 2 simultaneous users, though I haven’t tried in a while now).

The only thing I’m still struggling with is securing the coturn server. Other than that, yes, I consider my install complete, since unauthorized use of the instance should not be possible and guest users don’t have to have an account in my system. Both jitsi upstream and the module have improved significantly in these past two years!

1 Like