Skip to content

Commit

Permalink
change: DEVX-8554 Switch to JWT for client tokens
Browse files Browse the repository at this point in the history
  • Loading branch information
dragonmantank committed Aug 26, 2024
1 parent d18c642 commit fc5abe3
Show file tree
Hide file tree
Showing 6 changed files with 33 additions and 67 deletions.
12 changes: 8 additions & 4 deletions lib/generateJwt.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,17 @@
var jwt = require('jsonwebtoken');

module.exports = function (config) {
module.exports = function (config, additionalClaims) {
var currentTime = Math.floor(new Date() / 1000);
var token = jwt.sign({
const initialClaims = {
iss: config.apiKey,
ist: 'project',
iat: currentTime,
exp: currentTime + config.auth.expire
}, config.apiSecret);
exp: additionalClaims?.expire_time || currentTime + config.auth.expire
};

const claims = {...initialClaims, ...additionalClaims};

var token = jwt.sign(claims, config.apiSecret);

return token;
};
13 changes: 6 additions & 7 deletions lib/opentok.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
/*
'use strict';

/**
* OpenTok server-side SDK
*/

// Dependencies
var net = require('net');
var _ = require('lodash');
var encodeToken = require('opentok-token');
var Client = require('./client');
var Session = require('./session');
var Stream = require('./stream');
Expand Down Expand Up @@ -488,7 +489,6 @@ OpenTok = function (apiKey, apiSecret, env) {
);
};


/**
* Starts live captions for an OpenTok Session
* <p>
Expand Down Expand Up @@ -549,7 +549,6 @@ OpenTok = function (apiKey, apiSecret, env) {

this.startCaptions = captions.startCaptions.bind(null, apiConfig);


/**
* Stops live captions for an OpenTok Session
*
Expand Down Expand Up @@ -581,7 +580,6 @@ OpenTok = function (apiKey, apiSecret, env) {

this.stopCaptions = captions.stopCaptions.bind(null, apiConfig);


/**
* Retrieves a List of {@link Render} objects, representing any renders in the starting,
* started, stopped or failed state, for your API key.
Expand Down Expand Up @@ -2118,7 +2116,7 @@ OpenTok.prototype.createSession = function (opts, callback) {
*
* </ul>
*
* @return The token string.
* @return {String} The JWT Token that works for the client side
*/

OpenTok.prototype.generateToken = function (sessionId, opts) {
Expand Down Expand Up @@ -2200,8 +2198,9 @@ OpenTok.prototype.generateToken = function (sessionId, opts) {
+ 'concatenated length of less than 1024');
}

return encodeToken(tokenData, this.apiKey, this.apiSecret);
tokenData.scope = 'session.connect';

return generateJwt(this.client.c, tokenData);
};

/*
Expand Down
26 changes: 1 addition & 25 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 1 addition & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -82,8 +82,7 @@
"dependencies": {
"jsonwebtoken": "9.0.2",
"lodash": "4.17.21",
"node-fetch": "2.7.0",
"opentok-token": "1.1.1"
"node-fetch": "2.7.0"
},
"devDependencies": {
"chai": "4.3.10",
Expand Down
2 changes: 2 additions & 0 deletions test/helpers.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
'use strict';

// Test Helpers
var qs = require('querystring');
var crypto = require('crypto');
Expand Down
44 changes: 15 additions & 29 deletions test/opentok-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -907,11 +907,11 @@ describe('#generateToken', function () {
var token = this.opentok.generateToken(this.sessionId);
var decoded;
expect(token).to.be.a('string');
expect(helpers.verifyTokenSignature(token, apiSecret)).to.be.true;
decoded = helpers.decodeToken(token);
expect(decoded.partner_id).to.equal(apiKey);
decoded = jwt.verify(token, apiSecret);
expect(decoded.session_id).to.equal(this.sessionId);
expect(decoded.create_time).to.exist;
expect(decoded.nonce).to.exist;
expect(decoded.role).to.equal('publisher');
});

it('assigns a role in the token', function () {
Expand All @@ -920,18 +920,15 @@ describe('#generateToken', function () {
var decoded;
var subscriberToken;
expect(defaultRoleToken).to.be.a('string');
expect(helpers.verifyTokenSignature(defaultRoleToken, apiSecret)).to.be
.true;
decoded = helpers.decodeToken(defaultRoleToken);
decoded = jwt.verify(defaultRoleToken, apiSecret);
expect(decoded.role).to.equal('publisher');

// expects one with a valid role defined to set it
subscriberToken = this.opentok.generateToken(this.sessionId, {
role: 'subscriber'
});
expect(subscriberToken).to.be.a('string');
expect(helpers.verifyTokenSignature(subscriberToken, apiSecret)).to.be.true;
decoded = helpers.decodeToken(subscriberToken);
decoded = jwt.verify(subscriberToken, apiSecret);
expect(decoded.role).to.equal('subscriber');

// expects one with an invalid role to complain
Expand All @@ -953,24 +950,19 @@ describe('#generateToken', function () {
var inOneHour;
var oneHourAgo;

var fractionalExpireTime;
var roundedToken;

expect(defaultExpireToken).to.be.a('string');
expect(helpers.verifyTokenSignature(defaultExpireToken, apiSecret)).to.be
.true;
decoded = helpers.decodeToken(defaultExpireToken);
decoded = jwt.verify(defaultExpireToken, apiSecret);
expireTime = parseInt(decoded.expire_time, 10);
expect(expireTime).to.be.closeTo(inOneDay, delta);

// expects a token with an expiration time to have it
inOneHour = now + (60 * 60);
oneHourToken = this.opentok.generateToken(this.sessionId, {
expireTime: inOneHour
});
expect(oneHourToken).to.be.a('string');
expect(helpers.verifyTokenSignature(oneHourToken, apiSecret)).to.be.true;
decoded = helpers.decodeToken(oneHourToken);
decoded = jwt.verify(oneHourToken, apiSecret);
expireTime = parseInt(decoded.expire_time, 10);
expect(expireTime).to.be.closeTo(inOneHour, delta);

Expand All @@ -985,13 +977,12 @@ describe('#generateToken', function () {
}).to.throw(Error);

// rounds down fractional expiration time
fractionalExpireTime = now + 60.5;
const fractionalExpireTime = now + 60.5;
roundedToken = this.opentok.generateToken(this.sessionId, {
expireTime: fractionalExpireTime
});
expect(helpers.verifyTokenSignature(roundedToken, apiSecret)).to.be.true;
decoded = helpers.decodeToken(roundedToken);
expect(decoded.expire_time).to.equal(Math.round(fractionalExpireTime).toString());
decoded = jwt.verify(roundedToken, apiSecret);
expect(decoded.exp).to.equal(Math.round(fractionalExpireTime));
});

it('sets initial layout class list in the token', function () {
Expand All @@ -1000,19 +991,15 @@ describe('#generateToken', function () {
var layoutBearingToken = this.opentok.generateToken(this.sessionId, {
initialLayoutClassList: layoutClassList
});
var decoded = helpers.decodeToken(layoutBearingToken);
var decoded = jwt.verify(layoutBearingToken, apiSecret);
var singleLayoutBearingToken = this.opentok.generateToken(this.sessionId, {
initialLayoutClassList: singleLayoutClass
});

expect(layoutBearingToken).to.be.a('string');
expect(helpers.verifyTokenSignature(layoutBearingToken, apiSecret)).to.be
.true;
expect(decoded.initial_layout_class_list).to.equal(layoutClassList.join(' '));
expect(singleLayoutBearingToken).to.be.a('string');
expect(helpers.verifyTokenSignature(singleLayoutBearingToken, apiSecret)).to
.be.true;
decoded = helpers.decodeToken(singleLayoutBearingToken);
decoded = jwt.verify(singleLayoutBearingToken, apiSecret);
expect(decoded.initial_layout_class_list).to.equal(singleLayoutClass);

// NOTE: ignores invalid options instead of throwing an error, except if its too long
Expand All @@ -1032,9 +1019,7 @@ describe('#generateToken', function () {
data: sampleData
});
expect(dataBearingToken).to.be.a('string');
expect(helpers.verifyTokenSignature(dataBearingToken, apiSecret)).to.be
.true;
decoded = helpers.decodeToken(dataBearingToken);
decoded = jwt.verify(dataBearingToken, apiSecret);
expect(decoded.connection_data).to.equal(sampleData);

// expects a token with invalid connection data to complain
Expand Down Expand Up @@ -1066,8 +1051,9 @@ describe('#generateToken', function () {
this.opentok.generateToken(this.sessionId)
];
var nonces = _.map(tokens, function (token) {
return helpers.decodeToken(token).nonce;
return jwt.verify(token, apiSecret).nonce;
});

expect(_.uniq(nonces)).to.have.length(nonces.length);
});

Expand Down

0 comments on commit fc5abe3

Please sign in to comment.