Best Practices #
Avoid generating JWTs with unlimited or very long expiry.
Create short-lived JWTs that are valid only for a few minutes using
exp
claim in the payload.Add a
nbf
claim for scheduled meetings so that the host cannot create a meeting before meeting start time.Limit one JWT to a single room by setting
room
to the meetingroomName
instead of "*".Keep your api key safe and secret.
Until now we have been using static tokens for testing. We can use the following code snippets instead to generate JWTs on the go when someone creates a meeting.
Find and replace all instances of cm-consumer-id
with your Clan Meeting consumer ID in the code below.
Get your private SSH key file and replace cm-api-key.pem
in the code snippets below with the exact file name. Add relative file path if required.
Node.js #
Refer: https://github.com/auth0/node-jsonwebtoken
xxxxxxxxxx
11$ npm install jsonwebtoken
xxxxxxxxxx
271const jwt = require('jsonwebtoken');
2const fs = require('fs');
3
4const header = {
5 // TODO Edit this
6 keyid: "cm-consumer-id",
7 algorithm: "RS256"
8}
9
10const payLoad = {
11 // TODO Edit this
12 sub: "cm-consumer-id",
13 aud: "clanmeeting",
14 iss: "production",
15 // TODO Edit this
16 room: "specify-room-name-here",
17 exp: Math.floor(Date.now() / 1000) + (60 * 15), // token will be valid for 5 minutes only
18 nbf: Math.floor(Date.now() / 1000),
19 context: {},
20}
21
22// Synchronous sign
23const signature = fs.readFileSync('cm-api-key.pem');
24
25const token = jwt.sign(payLoad, signature, header);
26
27console.log(token);
PHP #
Refer: https://github.com/firebase/php-jwt
Use composer to manage your dependencies and download PHP-JWT:
xxxxxxxxxx
11composer require firebase/php-jwt
Optionally, install the paragonie/sodium_compat
package from composer if your php is < 7.2 or does not have libsodium installed:
xxxxxxxxxx
11composer require paragonie/sodium_compat
xxxxxxxxxx
281use Firebase\JWT\JWT;
2
3$now = time();
4$expiry_in_seconds = 60 * 15; // token will be valid for the next 15 minutes
5
6// TODO Edit this
7$header = "cm-consumer-id";
8
9$payload = array(
10 // TODO Edit this
11 "sub"=> "cm-consumer-id",
12 "aud"=> "clanmeeting",
13 "iss"=> "production",
14 // TODO Edit this
15 "room"=> "specify-room-name-here",
16 "exp"=> $now + $expiry_in_seconds,
17 "nbf"=> $now,
18 "context"=> array()
19);
20
21$private_key_file = url('cm-api-key.pem');
22
23$signature = openssl_pkey_get_private(
24 file_get_contents($private_key_file)
25);
26
27$token = JWT::encode($payload, $signature, 'RS256', $header);
28echo $token;
Python #
Refer: https://pyjwt.readthedocs.io/en/stable/usage.html#encoding-decoding-tokens-with-rs256-rsa
xxxxxxxxxx
11$ pip install pyjwt
xxxxxxxxxx
11$ pip install pyjwt[crypto]
xxxxxxxxxx
211import jwt
2import datetime
3
4header = {"kid": "cm-consumer-id"}
5
6now = datetime.datetime.utcnow()
7payload = {
8 "sub": "cm-consumer-id",
9 "aud": "clanmeeting",
10 "iss": "production",
11 "room": "specify-room-name-here",
12 "exp": now + datetime.timedelta(seconds=900), # e.g. User should login within the next 15 minutes.
13 "nbf": now,
14 "context": {}
15}
16
17with open('cm-api-key.pem','r') as file:
18 signature = file.read()
19
20token = jwt.encode(payload, signature, algorithm="RS256", headers=header)
21print(token)
Ruby #
Refer: https://github.com/jwt/ruby-jwt
Rubygems:
xxxxxxxxxx
11gem install jwt
Bundler:
Add the following to your Gemfile
xxxxxxxxxx
11gem 'jwt'
And run bundle install
xxxxxxxxxx
131require 'jwt'
2require 'openssl'
3
4# Please see above examples for payload
5payload = { foo: 'bar' }
6
7private_key_file = 'cm-api-key.pem';
8signature = OpenSSL::PKey::RSA.new(File.read 'private_key_file')
9
10# TODO edit kid
11token = JWT.encode payload, signature, 'RS256', header_fields= { kid: 'cm-consumer-id' }
12
13puts token
Java #
https://github.com/auth0/java-jwt
OR
Others #
RS256 algorithm should be supported by the library used to generate JWT.