This plugin implements a Prosody authentication provider that verifies a client connection based on a JWT described in RFC7519. It allows use of an external form of authentication with lib-jitsi-meet. Once your user authenticates you need to generate the JWT as described in the RFC and pass it to your client app. Once it connects with a valid token, it is considered authenticated by the jitsi-meet system.
During configuration, you can choose between two JWT validation methods:
In both cases you will need to provide the application ID that identifies the client.
For the Shared Secret Validation an application secret is shared by both the server (Prosody) and the JWT generation. Take a look at an example structure in Example Structure > Shared Secret Validation. Like described in the RFC, the shared secret is used to compute a HMAC hash value which allows authentication of the generated token. There are many existing libraries which can be used to implement token generation. More info can be found here: http://jwt.io/#libraries-io
For the Public Key Validation a key server must be provided via asap_key_server
to verify the token against a
provided public key on the given key server. An example structure can be view in Example Structure > Publiy Key Validation
This is how you generate the keys:
openssl genrsa -out keypair.pem 2048
openssl rsa -in keypair.pem -pubout -out publickey.pem
openssl pkcs8 -topk8 -inform PEM -outform DER -nocrypt -in keypair.pem -out moderated.der
Get the private_key_id through this command echo -n [NAME_OF_PRIVATE_KEY.der] | shasum -a 256 and change the publickey.pem name to the fetched private_key_id
JWT authentication works with BOSH and WebSocket connections.
The following JWT claims are used in the authentication token:
Sub with tenant If the ‘sub’ contains the tenant. You need to define the tenant in the muc
when creating a new JitsiConnection
in the options
within the hosts
section, see
const connection = new JitsiMeetJS.JitsiConnection(
'${applicationId}',
'${token}',
{
serviceUrl: 'wss://server.net/tenant/xmpp-websocket',
hosts: {
domain: 'muc.server.net',
muc: 'conference1.tenant.muc.server.net',
},
},
);
Different signature algorithm It is possible to define the algorithm type used, simply update the prosody.cfg.lua
file with your chosen type.
e.g signature_algorithm = "HS512"
For Shared Secret Validation the shared secret is used to compute the HMAC hash value and verify the token for HSXXX (e.g. HS256) tokens.
Alternatively for the Public Key Validation the token may be signed by a private key and authorized via a public
keyserver using RSXXX (e.g. RS256) tokens. In this mode, the ‘kid’ header of the JWT must be set to the name of the public key.
Prosody must be configured to fetch and confirm keys from a pre-configured public keyserver via asap_key_server
see Manual plugin configuration > 2.
In addition to the basic claims used in authentication, the token can also provide optional user display information in the ‘context’ field within the JWT payload. None of the information in the context field is used for token validation:
Note: At the moment all fields in ‘user’ need to be a valid string, numeric types or null
will generate an exception.
To retrieve the data from context
in lib-jitsi-meet you have to enable the Prosody module mod_presence_identity
in your config.
VirtualHost "jitmeet.example.com"
modules_enabled = { "presence_identity" }
The data is now available in the identity in the JitsiParticipant class. You can retrieve it by e.g. listening to
the USER_JOINED
event.
Note: The values in the token shall always be valid values. If you define e.g. the avatar as null
it will throw an
error.
There are two ways to validate the JWT. First one by Public Key Validation and the second one by a Shared Secret Validation.
The following examples shows the differences of both structures. For example the kid
key is only needed for public key
validation to define the public key to validate against.
Note: the context structure is optional for both, the secret shared and public key validation and is only needed to display personal information and for statistic purposes.
kid
must be the name of the public key to validate the token against.
{
"kid": "your_public_key_name",
"typ": "JWT",
"alg": "RS256"
}
{
"context": {
"user": {
"avatar": "https:/gravatar.com/avatar/abc123",
"name": "John Doe",
"email": "jdoe@example.com",
"id": "abcd:a1b2c3-d4e5f6-0abc1-23de-abcdef01fedcba"
},
"group": "a123-123-456-789"
},
"aud": "jitsi",
"iss": "my_client",
"sub": "meet.jit.si",
"room": "*",
"exp": 1500006923
}
{
"typ": "JWT",
"alg": "RS256"
}
{
"context": {
"user": {
"avatar": "https:/gravatar.com/avatar/abc123",
"name": "John Doe",
"email": "jdoe@example.com",
"id": "abcd:a1b2c3-d4e5f6-0abc1-23de-abcdef01fedcba"
},
"group": "a123-123-456-789"
},
"aud": "jitsi",
"iss": "my_client",
"sub": "meet.jit.si",
"room": "*",
"exp": 1500006923
}
JWT is currently checked in 2 places:
When JWT authentication is used with lib-jitsi-meet the token is passed to the JitsiConference constructor:
var token = {token_is_provided_by_your_application_possibly_after_some_authentication}
JitsiMeetJS.init(initOptions).then(function () {
connection = new JitsiMeetJS.JitsiConnection(APP_ID, token, options);
// ...
connection.connect();
});
In order to start a jitsi-meet conference with a token you need to specify the token as an URL param:
https://example.com/angrywhalesgrowhigh?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ
At the current level of integration every user that joins the conference has to provide the token and not just the one who creates the room. It should be possible to change that by using a second anonymous domain, but that hasn’t been tested yet.
Token authentication can be integrated automatically using a Debian package. Once you have jitsi-meet
installed
just install jitsi-meet-tokens
on top of it. In order to have it configured automatically at least version 779 of
jitsi-meet is required which comes with a special Prosody config template.
apt-get install jitsi-meet-tokens
Check the “Prosody Version” that is used in the deployment.
JWT authentication requires Prosody 0.11.6 or higher.
Make sure that /etc/prosody/prosody.cfg.lua contains the line below at the end to include meet host config. That’s because Prosody nightly may come with slightly different default config:
Include "conf.d/*.cfg.lua"
Restart the service to take the changes into account
sudo /etc/init.d/prosody restart
Modify your Prosody config with these three steps:
Adjust _pluginpaths to contain the path pointing to the jitsi meet Prosody plugins location. That’s where plugins are copied on jitsi-meet-token package installation. This should be included in the global config section (possibly at the beginning of your host config file).
plugin_paths = { "/usr/share/jitsi-meet/prosody-plugins/" }
Also, you need to set the global settings for token authorization. Both these options used to default to the ‘*’ parameter which means accept any issuer or audience string in incoming tokens, but that is no longer the case.
asap_accepted_issuers = { "*" }
asap_accepted_audiences = { "*" }
Under your domain config change authentication
to token
and provide the application ID in app_id
:
If you want to validate the token via Shared Secret Validation add the app_secret
parameter
VirtualHost "jitmeet.example.com"
authentication = "token";
app_id = "example_app_id"; -- application identifier
app_secret = "example_app_secret"; -- application secret known only to your token
-- generator and the plugin
allow_empty_token = false; -- tokens are verified only if they are supplied by the client
alternatively for the Public Key Validation you need to set an asap_key_server
to the base URL where valid/accepted
_public keys_ can be found by taking a sha256() of the `kid` field from the JWT header, and appending .pem to the end
```lua
VirtualHost "jitmeet.example.com"
authentication = "token";
app_id = "example_app_id"; -- application identifier
asap_key_server = "https://keyserver.example.com/asap"; -- URL for public keyserver storing keys by kid
allow_empty_token = false; -- tokens are verified only if they are supplied
```
Enable the room name token verification plugin in your MUC component config section:
Component "conference.jitmeet.example.com" "muc"
modules_enabled = { "token_verification" }