Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat!: Making AccessToken Identity required #875

Merged
merged 1 commit into from
Jan 6, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 8 additions & 6 deletions lib/jwt/AccessToken.ts
Original file line number Diff line number Diff line change
Expand Up @@ -79,9 +79,9 @@ export interface AccessTokenOptions {
*/
ttl?: number;
/**
* The identity of the first person
* The identity of the first person. Required.
*/
identity?: string;
identity: string;
/**
* Time from epoch in seconds for not before value
*/
Expand Down Expand Up @@ -329,7 +329,7 @@ export default class AccessToken implements AccessTokenOptions {
keySid: string;
secret: string;
ttl: number;
identity?: string;
identity: string;
nbf?: number;
region?: string;
grants: Grant<any, any, any>[];
Expand All @@ -340,15 +340,15 @@ export default class AccessToken implements AccessTokenOptions {
* @param secret - The secret to sign the token with
* @param options - ...
* @param options.ttl - Time to live in seconds (default 3600)
* @param options.identity - The identity of the first person
* @param options.identity - The identity of the first person. Required.
* @param options.nbf - Time from epoch in seconds for not before value
* @param options.region - The region value associated with this account
*/
constructor(
accountSid: string,
keySid: string,
secret: string,
options?: AccessTokenOptions
options: AccessTokenOptions
) {
if (!accountSid) {
throw new Error("accountSid is required");
Expand All @@ -359,7 +359,9 @@ export default class AccessToken implements AccessTokenOptions {
if (!secret) {
throw new Error("secret is required");
}
options = options || {};
if (!options || !options.identity) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this first !-check needed?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch, removed.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, I see. Or simply !options?.identity

throw new Error("identity is required to be specified in options");
}

this.accountSid = accountSid;
this.keySid = keySid;
Expand Down
75 changes: 36 additions & 39 deletions spec/unit/jwt/AccessToken.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,21 @@ describe("AccessToken", function () {
var accountSid = "ACaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
var keySid = "SKb5aed9ca12bf5890f37930e63cad6d38";

function getToken() {
return new twilio.jwt.AccessToken(accountSid, keySid, "secret", {
identity: "[email protected]",
});
}

describe("constructor", function () {
var initWithoutIndex = function (index) {
return function () {
var constructorArgs = [accountSid, keySid, "secret"];
var constructorArgs = [
accountSid,
keySid,
"secret",
{ identity: "foo" },
];
constructorArgs[index] = undefined;

// add context
Expand All @@ -30,6 +41,11 @@ describe("AccessToken", function () {
it("should require secret", function () {
expect(initWithoutIndex(2)).toThrow(new Error("secret is required"));
});
it("should require identity", function () {
expect(initWithoutIndex(3)).toThrow(
new Error("identity is required to be specified in options")
);
});
it("should convert identity from integer to string", function () {
var token = new twilio.jwt.AccessToken(accountSid, keySid, "secret", {
identity: 4444,
Expand All @@ -41,22 +57,18 @@ describe("AccessToken", function () {

describe("generate", function () {
describe("home region", function () {
var secret = "aTBl1PhJnykIjWll4TOiXKtD1ugxiz6f";

it("should add twr header when region is provided", function () {
var token = new twilio.jwt.AccessToken(accountSid, keySid, secret, {
region: "foo",
});
var token = getToken();
token.region = "foo";
var decoded = jwt.decode(token.toJwt(), { complete: true });

expect(decoded.header.twr).toBe("foo");
});

["", undefined, null, {}, 1, 0].forEach(function (value) {
it("should not add twr header if region is " + value, function () {
var token = new twilio.jwt.AccessToken(accountSid, keySid, secret, {
region: value,
});
var token = getToken();
token.region = value;
var decoded = jwt.decode(token.toJwt(), { complete: true });

expect(decoded.header.twr).toBe(undefined);
Expand All @@ -68,7 +80,8 @@ describe("AccessToken", function () {
var token = new twilio.jwt.AccessToken(
accountSid,
keySid,
"aTBl1PhJnykIjWll4TOiXKtD1ugxiz6f"
"aTBl1PhJnykIjWll4TOiXKtD1ugxiz6f",
{ identity: "foo" }
);
var decoded = jwt.decode(token.toJwt(), { complete: true });

Expand All @@ -81,7 +94,7 @@ describe("AccessToken", function () {

it("should accept different algorithms", function () {
var validateAlg = function (alg) {
var token = new twilio.jwt.AccessToken(accountSid, keySid, "secret");
var token = getToken();
var decoded = jwt.decode(token.toJwt(alg), {
complete: true,
algorithms: twilio.jwt.AccessToken.ALGORITHMS,
Expand All @@ -97,7 +110,8 @@ describe("AccessToken", function () {
it("should throw on invalid algorithm", function () {
var generateWithAlg = function (alg) {
return function () {
new twilio.jwt.AccessToken(accountSid, keySid, "secret").toJwt(alg);
var token = getToken();
token.toJwt(alg);
};
};

Expand All @@ -109,9 +123,7 @@ describe("AccessToken", function () {
});

it("should create a token without any grants", function () {
var token = new twilio.jwt.AccessToken(accountSid, keySid, "secret");
token.identity = "[email protected]";

var token = getToken();
var decoded = jwt.verify(token.toJwt(), "secret");
expect(decoded.jti.indexOf(keySid)).toBe(0);
expect(decoded.iss).toBe(keySid);
Expand All @@ -123,11 +135,9 @@ describe("AccessToken", function () {
});

it("should accept nbf", function () {
var token = getToken();
var nbf = Math.floor(Date.now() / 1000);
var token = new twilio.jwt.AccessToken(accountSid, keySid, "secret", {
nbf: nbf,
});
token.identity = "[email protected]";
token.nbf = nbf;

var decoded = jwt.verify(token.toJwt(), "secret");
expect(decoded.jti.indexOf(keySid)).toBe(0);
Expand All @@ -144,18 +154,15 @@ describe("AccessToken", function () {
});

it("should accept user defined ttl", function () {
var token = new twilio.jwt.AccessToken(accountSid, keySid, "secret");
var token = getToken();
token.ttl = 100;
token.identity = "[email protected]";

var decoded = jwt.verify(token.toJwt(), "secret");
expect(decoded.exp - decoded.iat).toBe(100);
});

it("should create token with chat grant", function () {
var token = new twilio.jwt.AccessToken(accountSid, keySid, "secret");
token.identity = "[email protected]";

var token = getToken();
var grant = new twilio.jwt.AccessToken.ChatGrant();
grant.serviceSid = "SRaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
grant.endpointId = "endpointId";
Expand All @@ -176,9 +183,7 @@ describe("AccessToken", function () {
});

it("should create token with video grant", function () {
var token = new twilio.jwt.AccessToken(accountSid, keySid, "secret");
token.identity = "[email protected]";

var token = getToken();
var grant = new twilio.jwt.AccessToken.VideoGrant();
grant.room = "room";
token.addGrant(grant);
Expand All @@ -193,9 +198,7 @@ describe("AccessToken", function () {
});

it("should create token with sync grant", function () {
var token = new twilio.jwt.AccessToken(accountSid, keySid, "secret");
token.identity = "[email protected]";

var token = getToken();
var grant = new twilio.jwt.AccessToken.SyncGrant();
grant.serviceSid = "ISaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
grant.endpointId = "endpointId";
Expand All @@ -212,9 +215,7 @@ describe("AccessToken", function () {
});

it("should create token with taskrouter grant", function () {
var token = new twilio.jwt.AccessToken(accountSid, keySid, "secret");
token.identity = "[email protected]";

var token = getToken();
var grant = new twilio.jwt.AccessToken.TaskRouterGrant();
grant.workspaceSid = "WSxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
grant.workerSid = "WKxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
Expand All @@ -233,9 +234,7 @@ describe("AccessToken", function () {
});

it("should create token with playback grant", function () {
var token = new twilio.jwt.AccessToken(accountSid, keySid, "secret");
token.identity = "[email protected]";

var token = getToken();
var playbackGrant = {
requestCredentials: null,
playbackUrl:
Expand All @@ -255,9 +254,7 @@ describe("AccessToken", function () {
});

it("should create token with multiple grants", function () {
var token = new twilio.jwt.AccessToken(accountSid, keySid, "secret");
token.identity = "[email protected]";

var token = getToken();
var grant = new twilio.jwt.AccessToken.ChatGrant();
grant.serviceSid = "SRaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
grant.endpointId = "endpointId";
Expand Down