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

Adding access_token validation for RS256 id_token's #709

Merged
merged 4 commits into from
Mar 22, 2018
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
2 changes: 1 addition & 1 deletion example/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -203,7 +203,7 @@ <h2>Console:</h2>
domain: 'brucke.auth0.com',
redirectUri: 'https://localhost:3000/example/',
clientID: 'k5u3o2fiAA8XweXEEX604KCwCjzjtMU6',
responseType: 'token',
responseType: 'token id_token',
plugins: [
new CordovaAuth0Plugin()
]
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@
"license": "MIT",
"dependencies": {
"base64-js": "^1.2.0",
"idtoken-verifier": "^1.1.2",
"idtoken-verifier": "^1.2.0",
"qs": "^6.4.0",
"superagent": "^3.8.2",
"url-join": "^1.1.0",
Expand Down
4 changes: 2 additions & 2 deletions src/helper/error.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,11 @@ function buildResponse(error, description) {
};
}

function invalidJwt(description) {
function invalidToken(description) {
Copy link
Contributor

Choose a reason for hiding this comment

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

can this be considered a breaking change?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

nope. not a public method. just used internally.

return buildResponse('invalid_token', description);
}

module.exports = {
buildResponse: buildResponse,
invalidJwt: invalidJwt
invalidToken: invalidToken
};
19 changes: 17 additions & 2 deletions src/web-auth/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -246,7 +246,22 @@ WebAuth.prototype.validateAuthenticationResponse = function(options, parsedHash,
payload
) {
if (!validationError) {
return callback(null, payload);
if (!parsedHash.access_token) {
return callback(null, payload);
}
// here we're absolutely sure that the id_token's alg is RS256
// and that the id_token is valid, so we can check the access_token
return new IdTokenVerifier().validateAccessToken(
parsedHash.access_token,
'RS256',
payload.at_hash,
function(err) {
if (err) {
return callback(error.invalidToken(err.message));
}
return callback(null, payload);
}
);
}
if (validationError.error !== 'invalid_token') {
return callback(validationError);
Expand Down Expand Up @@ -307,7 +322,7 @@ WebAuth.prototype.validateToken = function(token, nonce, cb) {

verifier.verify(token, nonce, function(err, payload) {
if (err) {
return cb(error.invalidJwt(err.message));
return cb(error.invalidToken(err.message));
}

cb(null, payload);
Expand Down
5 changes: 5 additions & 0 deletions test/plugins/cordova.test.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
var IdTokenVerifier = require('idtoken-verifier');
var expect = require('expect.js');
var stub = require('sinon').stub;

Expand Down Expand Up @@ -100,6 +101,9 @@ describe('auth0.plugins.cordova', function() {

context('PopupHandler', function() {
beforeEach(function() {
stub(IdTokenVerifier.prototype, 'validateAccessToken', function(at, alg, atHash, cb) {
cb(null);
});
var _this = this;
this.events = {};
var webAuth = new WebAuth({
Expand Down Expand Up @@ -132,6 +136,7 @@ describe('auth0.plugins.cordova', function() {
});

afterEach(function() {
IdTokenVerifier.prototype.validateAccessToken.restore();
delete global.window;
this.events = null;
this.popupHandler = null;
Expand Down
127 changes: 125 additions & 2 deletions test/web-auth/web-auth.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ var expect = require('expect.js');
var stub = require('sinon').stub;
var spy = require('sinon').spy;
var request = require('superagent');
var IdTokenVerifier = require('idtoken-verifier');

var storage = require('../../src/helper/storage');
var windowHelper = require('../../src/helper/window');
Expand Down Expand Up @@ -271,9 +272,18 @@ describe('auth0.WebAuth', function() {

beforeEach(function() {
spy(ssodata, 'set');
stub(IdTokenVerifier.prototype, 'validateAccessToken', function(at, alg, atHash, cb) {
cb(null);
});
});
afterEach(function() {
ssodata.set.restore();
if (IdTokenVerifier.prototype.validateAccessToken.restore) {
IdTokenVerifier.prototype.validateAccessToken.restore();
}
if (WebAuth.prototype.validateToken.restore) {
WebAuth.prototype.validateToken.restore();
}
});

it('should parse a valid hash without id_token', function(done) {
Expand Down Expand Up @@ -307,6 +317,120 @@ describe('auth0.WebAuth', function() {
}
); // eslint-disable-line
});
it('should return the id_token payload when there is no access_token', function(done) {
Copy link
Contributor

Choose a reason for hiding this comment

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

shouldn't the payload also be returned when there's a VALID access token? That's the missing test case IMO, even if it's 95% similar to this

var webAuth = new WebAuth({
domain: 'brucke.auth0.com',
redirectUri: 'http://example.com/callback',
clientID: 'k5u3o2fiAA8XweXEEX604KCwCjzjtMU6',
responseType: 'id_token',
__disableExpirationCheck: true
});

var data = webAuth.parseHash(
{
hash: '#state=foo&token_type=Bearer&id_token=eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImtpZCI6Ik5FVkJOVU5CT1RneFJrRTVOa1F6UXpjNE9UQkVNRUZGUkRRNU4wUTJRamswUmtRMU1qRkdNUSJ9.eyJuaWNrbmFtZSI6ImpvaG5mb28iLCJuYW1lIjoiam9obmZvb0BnbWFpbC5jb20iLCJwaWN0dXJlIjoiaHR0cHM6Ly9zLmdyYXZhdGFyLmNvbS9hdmF0YXIvMzhmYTAwMjQyM2JkOGM5NDFjNmVkMDU4OGI2MGZmZWQ_cz00ODAmcj1wZyZkPWh0dHBzJTNBJTJGJTJGY2RuLmF1dGgwLmNvbSUyRmF2YXRhcnMlMkZqby5wbmciLCJ1cGRhdGVkX2F0IjoiMjAxOC0wMy0xNFQxNjozNDo1Ni40MjNaIiwiZW1haWwiOiJqb2huZm9vQGdtYWlsLmNvbSIsImVtYWlsX3ZlcmlmaWVkIjpmYWxzZSwiaXNzIjoiaHR0cHM6Ly9icnVja2UuYXV0aDAuY29tLyIsInN1YiI6ImF1dGgwfDVhMjA1NGZmNDUxNTc3MTFiZTgxODJmNCIsImF1ZCI6Ims1dTNvMmZpQUE4WHdlWEVFWDYwNEtDd0Nqemp0TVU2IiwiaWF0IjoxNTIxMDQ1Mjk2LCJleHAiOjE1MjEwODEyOTYsImF0X2hhc2giOiJjZHVrb2FVc3dNOWJvX3l6cmdWY3J3Iiwibm9uY2UiOiJsRkNuSTguY3JSVGRIZmRvNWsuek1YZlIzMTg1NmdLeiJ9.U4_F5Zw6xYVoHGiiem1wjz7i9eRaSOrt-L1e6hlu3wmqA-oNuVqf1tEYD9u0z5AbXXbQSr491A3VvUbLKjws13XETcljhaqigZ9q4HBpmzPlrUGmPreBLVQgGOaq5NVAViFTvORxYCMFLlc-SE6QI6xWF0AhFpoW7-hkOcOzXWAXqhkMgwAfjJ9aeOzSBgblmtx4duyNESBRefd3XPQrakWjGIqH3dFdc-lDFbY76eSLYfBi4AH-yim4egzB6LYOC-e2huZcHdmRAmEQaKZ7D7COBiGsgAPVGyjZtqfSQ2CRwNrAbxDwi8BqlLhQePOs6d3hqV-3OPLfdE6dUFh2DQ',
nonce: 'lFCnI8.crRTdHfdo5k.zMXfR31856gKz'
},
function(err, data) {
expect(err).to.be(null);
expect(data).to.be.eql({
accessToken: null,
idToken: 'eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImtpZCI6Ik5FVkJOVU5CT1RneFJrRTVOa1F6UXpjNE9UQkVNRUZGUkRRNU4wUTJRamswUmtRMU1qRkdNUSJ9.eyJuaWNrbmFtZSI6ImpvaG5mb28iLCJuYW1lIjoiam9obmZvb0BnbWFpbC5jb20iLCJwaWN0dXJlIjoiaHR0cHM6Ly9zLmdyYXZhdGFyLmNvbS9hdmF0YXIvMzhmYTAwMjQyM2JkOGM5NDFjNmVkMDU4OGI2MGZmZWQ_cz00ODAmcj1wZyZkPWh0dHBzJTNBJTJGJTJGY2RuLmF1dGgwLmNvbSUyRmF2YXRhcnMlMkZqby5wbmciLCJ1cGRhdGVkX2F0IjoiMjAxOC0wMy0xNFQxNjozNDo1Ni40MjNaIiwiZW1haWwiOiJqb2huZm9vQGdtYWlsLmNvbSIsImVtYWlsX3ZlcmlmaWVkIjpmYWxzZSwiaXNzIjoiaHR0cHM6Ly9icnVja2UuYXV0aDAuY29tLyIsInN1YiI6ImF1dGgwfDVhMjA1NGZmNDUxNTc3MTFiZTgxODJmNCIsImF1ZCI6Ims1dTNvMmZpQUE4WHdlWEVFWDYwNEtDd0Nqemp0TVU2IiwiaWF0IjoxNTIxMDQ1Mjk2LCJleHAiOjE1MjEwODEyOTYsImF0X2hhc2giOiJjZHVrb2FVc3dNOWJvX3l6cmdWY3J3Iiwibm9uY2UiOiJsRkNuSTguY3JSVGRIZmRvNWsuek1YZlIzMTg1NmdLeiJ9.U4_F5Zw6xYVoHGiiem1wjz7i9eRaSOrt-L1e6hlu3wmqA-oNuVqf1tEYD9u0z5AbXXbQSr491A3VvUbLKjws13XETcljhaqigZ9q4HBpmzPlrUGmPreBLVQgGOaq5NVAViFTvORxYCMFLlc-SE6QI6xWF0AhFpoW7-hkOcOzXWAXqhkMgwAfjJ9aeOzSBgblmtx4duyNESBRefd3XPQrakWjGIqH3dFdc-lDFbY76eSLYfBi4AH-yim4egzB6LYOC-e2huZcHdmRAmEQaKZ7D7COBiGsgAPVGyjZtqfSQ2CRwNrAbxDwi8BqlLhQePOs6d3hqV-3OPLfdE6dUFh2DQ',
idTokenPayload: {
nickname: 'johnfoo',
name: '[email protected]',
picture: 'https://s.gravatar.com/avatar/38fa002423bd8c941c6ed0588b60ffed?s=480&r=pg&d=https%3A%2F%2Fcdn.auth0.com%2Favatars%2Fjo.png',
updated_at: '2018-03-14T16:34:56.423Z',
email: '[email protected]',
email_verified: false,
iss: 'https://brucke.auth0.com/',
sub: 'auth0|5a2054ff45157711be8182f4',
aud: 'k5u3o2fiAA8XweXEEX604KCwCjzjtMU6',
iat: 1521045296,
exp: 1521081296,
at_hash: 'cdukoaUswM9bo_yzrgVcrw',
nonce: 'lFCnI8.crRTdHfdo5k.zMXfR31856gKz'
},
appState: null,
refreshToken: null,
state: 'foo',
expiresIn: null,
tokenType: 'Bearer',
scope: null
});
done();
}
); // eslint-disable-line
});
it('should return the id_token payload when there is a valid access_token', function(done) {
var webAuth = new WebAuth({
domain: 'brucke.auth0.com',
redirectUri: 'http://example.com/callback',
clientID: 'k5u3o2fiAA8XweXEEX604KCwCjzjtMU6',
responseType: 'token id_token',
__disableExpirationCheck: true
});

var data = webAuth.parseHash(
{
hash: '#state=foo&token_type=Bearer&access_token=L11oiFDHj3zmZid1AnsEuggXcMfjqe0X&id_token=eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImtpZCI6Ik5FVkJOVU5CT1RneFJrRTVOa1F6UXpjNE9UQkVNRUZGUkRRNU4wUTJRamswUmtRMU1qRkdNUSJ9.eyJuaWNrbmFtZSI6ImpvaG5mb28iLCJuYW1lIjoiam9obmZvb0BnbWFpbC5jb20iLCJwaWN0dXJlIjoiaHR0cHM6Ly9zLmdyYXZhdGFyLmNvbS9hdmF0YXIvMzhmYTAwMjQyM2JkOGM5NDFjNmVkMDU4OGI2MGZmZWQ_cz00ODAmcj1wZyZkPWh0dHBzJTNBJTJGJTJGY2RuLmF1dGgwLmNvbSUyRmF2YXRhcnMlMkZqby5wbmciLCJ1cGRhdGVkX2F0IjoiMjAxOC0wMy0yMVQyMDowNDo0Mi40OTNaIiwiZW1haWwiOiJqb2huZm9vQGdtYWlsLmNvbSIsImVtYWlsX3ZlcmlmaWVkIjpmYWxzZSwiaXNzIjoiaHR0cHM6Ly9icnVja2UuYXV0aDAuY29tLyIsInN1YiI6ImF1dGgwfDVhMjA1NGZmNDUxNTc3MTFiZTgxODJmNCIsImF1ZCI6Ims1dTNvMmZpQUE4WHdlWEVFWDYwNEtDd0Nqemp0TVU2IiwiaWF0IjoxNTIxNjYyNjgyLCJleHAiOjE1MjE2OTg2ODIsImF0X2hhc2giOiJKS2NaM3hTQ2NGVEE5NkxuQ3lJX0FRIiwibm9uY2UiOiJLdlhoc1VIc2VJSEl5emF1X2JVflJHQ2t1RUFDTE5HaiJ9.UbiWFikCkoX-m22mFnXJhKMY8M9BGMDJqZZ5J-iUAQwOmD-33-zX-AjSbD6zL6sOJoKJratJLtLa90tE3sDeokI9c8GE_JonfeF95knVPAx99tD5eCIJabV8HN_K1rfcgI_ed9v8RKQD9_dRkwUMHgXyceWeijnA9k8jG-pe1iXAtnn386G5s6fj-do8SUvC2MFWNmD5VhkW-CyEg_Chui8BoOSM9d7liMZRQkgKA2aGl5t2qqvOu0ZNJwaWoeQ5T0R-h2Yk6Om_alFKyLdZXsZY2LRYQdbk4nEgxY59241HPZGHYOTJN5uLlbcxKyouTyM7Gt4dE76wyRh9kBr47A',
nonce: 'KvXhsUHseIHIyzau_bU~RGCkuEACLNGj'
},
function(err, data) {
expect(err).to.be(null);
expect(data).to.be.eql({
accessToken: 'L11oiFDHj3zmZid1AnsEuggXcMfjqe0X',
idToken: 'eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImtpZCI6Ik5FVkJOVU5CT1RneFJrRTVOa1F6UXpjNE9UQkVNRUZGUkRRNU4wUTJRamswUmtRMU1qRkdNUSJ9.eyJuaWNrbmFtZSI6ImpvaG5mb28iLCJuYW1lIjoiam9obmZvb0BnbWFpbC5jb20iLCJwaWN0dXJlIjoiaHR0cHM6Ly9zLmdyYXZhdGFyLmNvbS9hdmF0YXIvMzhmYTAwMjQyM2JkOGM5NDFjNmVkMDU4OGI2MGZmZWQ_cz00ODAmcj1wZyZkPWh0dHBzJTNBJTJGJTJGY2RuLmF1dGgwLmNvbSUyRmF2YXRhcnMlMkZqby5wbmciLCJ1cGRhdGVkX2F0IjoiMjAxOC0wMy0yMVQyMDowNDo0Mi40OTNaIiwiZW1haWwiOiJqb2huZm9vQGdtYWlsLmNvbSIsImVtYWlsX3ZlcmlmaWVkIjpmYWxzZSwiaXNzIjoiaHR0cHM6Ly9icnVja2UuYXV0aDAuY29tLyIsInN1YiI6ImF1dGgwfDVhMjA1NGZmNDUxNTc3MTFiZTgxODJmNCIsImF1ZCI6Ims1dTNvMmZpQUE4WHdlWEVFWDYwNEtDd0Nqemp0TVU2IiwiaWF0IjoxNTIxNjYyNjgyLCJleHAiOjE1MjE2OTg2ODIsImF0X2hhc2giOiJKS2NaM3hTQ2NGVEE5NkxuQ3lJX0FRIiwibm9uY2UiOiJLdlhoc1VIc2VJSEl5emF1X2JVflJHQ2t1RUFDTE5HaiJ9.UbiWFikCkoX-m22mFnXJhKMY8M9BGMDJqZZ5J-iUAQwOmD-33-zX-AjSbD6zL6sOJoKJratJLtLa90tE3sDeokI9c8GE_JonfeF95knVPAx99tD5eCIJabV8HN_K1rfcgI_ed9v8RKQD9_dRkwUMHgXyceWeijnA9k8jG-pe1iXAtnn386G5s6fj-do8SUvC2MFWNmD5VhkW-CyEg_Chui8BoOSM9d7liMZRQkgKA2aGl5t2qqvOu0ZNJwaWoeQ5T0R-h2Yk6Om_alFKyLdZXsZY2LRYQdbk4nEgxY59241HPZGHYOTJN5uLlbcxKyouTyM7Gt4dE76wyRh9kBr47A',
idTokenPayload: {
nickname: 'johnfoo',
name: '[email protected]',
picture: 'https://s.gravatar.com/avatar/38fa002423bd8c941c6ed0588b60ffed?s=480&r=pg&d=https%3A%2F%2Fcdn.auth0.com%2Favatars%2Fjo.png',
updated_at: '2018-03-21T20:04:42.493Z',
email: '[email protected]',
email_verified: false,
iss: 'https://brucke.auth0.com/',
sub: 'auth0|5a2054ff45157711be8182f4',
aud: 'k5u3o2fiAA8XweXEEX604KCwCjzjtMU6',
iat: 1521662682,
exp: 1521698682,
at_hash: 'JKcZ3xSCcFTA96LnCyI_AQ',
nonce: 'KvXhsUHseIHIyzau_bU~RGCkuEACLNGj'
},
appState: null,
refreshToken: null,
state: 'foo',
expiresIn: null,
tokenType: 'Bearer',
scope: null
});
done();
}
); // eslint-disable-line
});
it('should validate an access_token when available', function(done) {
Copy link
Contributor

Choose a reason for hiding this comment

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

I don't know if you are using the same convention somewhere, but I'd say:

should throw a token validation error when the access_token is available but not valid

Copy link
Contributor Author

Choose a reason for hiding this comment

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

image

var webAuth = new WebAuth({
domain: 'brucke.auth0.com',
redirectUri: 'http://example.com/callback',
clientID: 'k5u3o2fiAA8XweXEEX604KCwCjzjtMU6',
responseType: 'token id_token',
__disableExpirationCheck: true
});
IdTokenVerifier.prototype.validateAccessToken.restore();

var data = webAuth.parseHash(
{
hash: '#state=foo&token_type=Bearer&access_token=YTvJcYrrZYHUXLZK5leLnfmD5ZIA_EA&id_token=eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImtpZCI6Ik5FVkJOVU5CT1RneFJrRTVOa1F6UXpjNE9UQkVNRUZGUkRRNU4wUTJRamswUmtRMU1qRkdNUSJ9.eyJuaWNrbmFtZSI6ImpvaG5mb28iLCJuYW1lIjoiam9obmZvb0BnbWFpbC5jb20iLCJwaWN0dXJlIjoiaHR0cHM6Ly9zLmdyYXZhdGFyLmNvbS9hdmF0YXIvMzhmYTAwMjQyM2JkOGM5NDFjNmVkMDU4OGI2MGZmZWQ_cz00ODAmcj1wZyZkPWh0dHBzJTNBJTJGJTJGY2RuLmF1dGgwLmNvbSUyRmF2YXRhcnMlMkZqby5wbmciLCJ1cGRhdGVkX2F0IjoiMjAxOC0wMy0xNFQxNjozNDo1Ni40MjNaIiwiZW1haWwiOiJqb2huZm9vQGdtYWlsLmNvbSIsImVtYWlsX3ZlcmlmaWVkIjpmYWxzZSwiaXNzIjoiaHR0cHM6Ly9icnVja2UuYXV0aDAuY29tLyIsInN1YiI6ImF1dGgwfDVhMjA1NGZmNDUxNTc3MTFiZTgxODJmNCIsImF1ZCI6Ims1dTNvMmZpQUE4WHdlWEVFWDYwNEtDd0Nqemp0TVU2IiwiaWF0IjoxNTIxMDQ1Mjk2LCJleHAiOjE1MjEwODEyOTYsImF0X2hhc2giOiJjZHVrb2FVc3dNOWJvX3l6cmdWY3J3Iiwibm9uY2UiOiJsRkNuSTguY3JSVGRIZmRvNWsuek1YZlIzMTg1NmdLeiJ9.U4_F5Zw6xYVoHGiiem1wjz7i9eRaSOrt-L1e6hlu3wmqA-oNuVqf1tEYD9u0z5AbXXbQSr491A3VvUbLKjws13XETcljhaqigZ9q4HBpmzPlrUGmPreBLVQgGOaq5NVAViFTvORxYCMFLlc-SE6QI6xWF0AhFpoW7-hkOcOzXWAXqhkMgwAfjJ9aeOzSBgblmtx4duyNESBRefd3XPQrakWjGIqH3dFdc-lDFbY76eSLYfBi4AH-yim4egzB6LYOC-e2huZcHdmRAmEQaKZ7D7COBiGsgAPVGyjZtqfSQ2CRwNrAbxDwi8BqlLhQePOs6d3hqV-3OPLfdE6dUFh2DQ',
nonce: 'lFCnI8.crRTdHfdo5k.zMXfR31856gKz'
},
function(err, data) {
expect(err).to.be.eql({
error: 'invalid_token',
errorDescription: 'Invalid access_token'
});
done();
}
); // eslint-disable-line
});

context('when there is a transaction', function() {
it('should return transaction.appState', function(done) {
Expand Down Expand Up @@ -824,7 +948,7 @@ describe('auth0.WebAuth', function() {
domain: 'mdocs_2.auth0.com',
redirectUri: 'http://example.com/callback',
clientID: '0HP71GSd6PuoRYJ3DXKdiXCUUdGmBbup',
responseType: 'token'
responseType: 'id_token'
});

var data = webAuth.parseHash(
Expand Down Expand Up @@ -880,7 +1004,6 @@ describe('auth0.WebAuth', function() {
},
function(err, data) {
expect(err).to.be.eql(expectedError);
WebAuth.prototype.validateToken.restore();
done();
}
);
Expand Down
6 changes: 3 additions & 3 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -1956,9 +1956,9 @@ husky@^0.13.3:
is-ci "^1.0.9"
normalize-path "^1.0.0"

idtoken-verifier@^1.1.2:
version "1.1.2"
resolved "https://registry.yarnpkg.com/idtoken-verifier/-/idtoken-verifier-1.1.2.tgz#bd5125aaccc221c1e0c57c9393dc68c0f7134b69"
idtoken-verifier@^1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/idtoken-verifier/-/idtoken-verifier-1.2.0.tgz#4654f1f07ab7a803fc9b1b8b36057e2a87ad8b09"
dependencies:
base64-js "^1.2.0"
crypto-js "^3.1.9-1"
Expand Down