Socket
Socket
Sign inDemoInstall

openid-client

Package Overview
Dependencies
Maintainers
1
Versions
181
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

openid-client - npm Package Compare versions

Comparing version 1.5.3 to 1.6.0

6

CHANGELOG.md

@@ -8,2 +8,3 @@ # openid-client CHANGELOG

<!-- TOC START min:2 max:2 link:true update:true -->
- [Version 1.6.0](#version-160)
- [Version 1.5.0](#version-150)

@@ -20,2 +21,7 @@ - [Version 1.4.0](#version-140)

## Version 1.6.0
- [DIFF](https://github.com/panva/node-openid-client/compare/v1.5.3...v1.6.0)
- added at_hash presence assertion for applicable (implicit) ID Token validation
- added c_hash presence assertion for applicable (hybrid) ID Token validation from the authorization_endpoint
## Version 1.5.0

@@ -22,0 +28,0 @@ ### Version 1.5.3

174

lib/client.js

@@ -142,2 +142,6 @@ 'use strict';

class Client {
/**
* @name constructor
* @api public
*/
constructor(metadata, keystore) {

@@ -164,2 +168,6 @@ const recognized = _.chain(metadata)

/**
* @name authorizationUrl
* @api public
*/
authorizationUrl(params) {

@@ -172,2 +180,6 @@ return url.format(_.defaults({

/**
* @name authorizationPost
* @api public
*/
authorizationPost(params) {

@@ -190,2 +202,6 @@ const inputs = authorizationParams.call(this, params);

/**
* @name callbackParams
* @api public
*/
callbackParams(input) { // eslint-disable-line

@@ -230,2 +246,6 @@ const isIncomingMessage = input instanceof http.IncomingMessage;

/**
* @name authorizationCallback
* @api public
*/
authorizationCallback(redirectUri, parameters, checks) {

@@ -250,3 +270,3 @@ const params = _.pick(parameters, CALLBACK_PROPERTIES);

.then(tokenset => this.decryptIdToken(tokenset, 'id_token'))
.then(tokenset => this.validateIdToken(tokenset, toCheck.nonce, 'id_token', toCheck.max_age));
.then(tokenset => this.validateIdToken(tokenset, toCheck.nonce, 'authorization', toCheck.max_age));
}

@@ -261,3 +281,3 @@

.then(tokenset => this.decryptIdToken(tokenset, 'id_token'))
.then(tokenset => this.validateIdToken(tokenset, toCheck.nonce, 'id_token', toCheck.max_age))
.then(tokenset => this.validateIdToken(tokenset, toCheck.nonce, 'token', toCheck.max_age))
.then((tokenset) => {

@@ -308,7 +328,6 @@ if (params.session_state) tokenset.session_state = params.session_state;

const header = idToken.split('.')[0];
const headerObject = JSON.parse(base64url.decode(header));
const header = JSON.parse(base64url.decode(idToken.split('.')[0]));
assert.equal(headerObject.alg, expectedAlg, 'unexpected alg received');
assert.equal(headerObject.enc, expectedEnc, 'unexpected enc received');
assert.equal(header.alg, expectedAlg, 'unexpected alg received');
assert.equal(header.enc, expectedEnc, 'unexpected enc received');

@@ -328,17 +347,11 @@ const keystoreOrSecret = expectedAlg.match(/^(RSA|ECDH)/) ?

validateIdToken(token, nonce, intent, maxAge) {
let idToken = token;
/**
* @name validateIdToken
* @api private
*/
validateIdToken(tokenSet, nonce, returnedBy, maxAge) {
let idToken = tokenSet;
const use = (() => {
switch (intent) {
case 'id_token':
case 'userinfo':
return intent;
default:
return 'id_token';
}
})();
const expectedAlg = (() => {
if (use === 'userinfo') return this.userinfo_signed_response_alg;
if (returnedBy === 'userinfo') return this.userinfo_signed_response_alg;
return this.id_token_signed_response_alg;

@@ -361,9 +374,7 @@ })();

const parts = idToken.split('.');
const header = parts[0];
const payload = parts[1];
const headerObject = JSON.parse(base64url.decode(header));
const payloadObject = JSON.parse(base64url.decode(payload));
const header = JSON.parse(base64url.decode(parts[0]));
const payload = JSON.parse(base64url.decode(parts[1]));
const verifyPresence = (prop) => {
if (payloadObject[prop] === undefined) {
if (payload[prop] === undefined) {
throw new Error(`missing required JWT property ${prop}`);

@@ -373,44 +384,44 @@ }

assert.equal(headerObject.alg, expectedAlg, 'unexpected algorithm received');
assert.equal(header.alg, expectedAlg, 'unexpected algorithm received');
if (use === 'id_token') {
if (returnedBy !== 'userinfo') {
['iss', 'sub', 'aud', 'exp', 'iat'].forEach(verifyPresence);
}
if (payloadObject.iss !== undefined) {
assert.equal(this.issuer.issuer, payloadObject.iss, 'unexpected iss value');
if (payload.iss !== undefined) {
assert.equal(this.issuer.issuer, payload.iss, 'unexpected iss value');
}
if (payloadObject.iat !== undefined) {
assert.equal(typeof payloadObject.iat, 'number', 'iat is not a number');
assert(payloadObject.iat <= timestamp + this.CLOCK_TOLERANCE, 'id_token issued in the future');
if (payload.iat !== undefined) {
assert.equal(typeof payload.iat, 'number', 'iat is not a number');
assert(payload.iat <= timestamp + this.CLOCK_TOLERANCE, 'id_token issued in the future');
}
if (payloadObject.nbf !== undefined) {
assert.equal(typeof payloadObject.nbf, 'number', 'nbf is not a number');
assert(payloadObject.nbf <= timestamp + this.CLOCK_TOLERANCE, 'id_token not active yet');
if (payload.nbf !== undefined) {
assert.equal(typeof payload.nbf, 'number', 'nbf is not a number');
assert(payload.nbf <= timestamp + this.CLOCK_TOLERANCE, 'id_token not active yet');
}
if (maxAge || (maxAge !== null && this.require_auth_time)) {
assert(payloadObject.auth_time, 'missing required JWT property auth_time');
assert.equal(typeof payloadObject.auth_time, 'number', 'auth_time is not a number');
assert(payload.auth_time, 'missing required JWT property auth_time');
assert.equal(typeof payload.auth_time, 'number', 'auth_time is not a number');
}
if (maxAge) {
assert(payloadObject.auth_time + maxAge >= timestamp - this.CLOCK_TOLERANCE, 'too much time has elapsed since the last End-User authentication');
assert(payload.auth_time + maxAge >= timestamp - this.CLOCK_TOLERANCE, 'too much time has elapsed since the last End-User authentication');
}
if (nonce !== null && (payloadObject.nonce || nonce !== undefined)) {
assert.equal(payloadObject.nonce, nonce, 'nonce mismatch');
if (nonce !== null && (payload.nonce || nonce !== undefined)) {
assert.equal(payload.nonce, nonce, 'nonce mismatch');
}
if (payloadObject.exp !== undefined) {
assert.equal(typeof payloadObject.exp, 'number', 'exp is not a number');
assert(timestamp - this.CLOCK_TOLERANCE < payloadObject.exp, 'id_token expired');
if (payload.exp !== undefined) {
assert.equal(typeof payload.exp, 'number', 'exp is not a number');
assert(timestamp - this.CLOCK_TOLERANCE < payload.exp, 'id_token expired');
}
if (payloadObject.aud !== undefined) {
if (!Array.isArray(payloadObject.aud)) {
payloadObject.aud = [payloadObject.aud];
} else if (payloadObject.aud.length > 1 && !payloadObject.azp) {
if (payload.aud !== undefined) {
if (!Array.isArray(payload.aud)) {
payload.aud = [payload.aud];
} else if (payload.aud.length > 1 && !payload.azp) {
throw new Error('missing required JWT property azp');

@@ -420,29 +431,38 @@ }

if (payloadObject.azp !== undefined) {
assert.equal(this.client_id, payloadObject.azp, 'azp must be the client_id');
if (payload.azp !== undefined) {
assert.equal(this.client_id, payload.azp, 'azp must be the client_id');
}
if (payloadObject.aud !== undefined) {
assert(payloadObject.aud.indexOf(this.client_id) !== -1, 'aud is missing the client_id');
if (payload.aud !== undefined) {
assert(payload.aud.indexOf(this.client_id) !== -1, 'aud is missing the client_id');
}
if (isTokenSet && payloadObject.at_hash !== undefined) {
assert(tokenHash(payloadObject.at_hash, token.access_token), 'at_hash mismatch');
if (returnedBy === 'authorization') {
assert(payload.at_hash || !tokenSet.access_token, 'missing required property at_hash');
assert(payload.c_hash || !tokenSet.code, 'missing required property c_hash');
}
if (isTokenSet && payloadObject.c_hash !== undefined && token.code) {
assert(tokenHash(payloadObject.c_hash, token.code), 'c_hash mismatch');
if (tokenSet.access_token && payload.at_hash !== undefined) {
assert(tokenHash(payload.at_hash, tokenSet.access_token), 'at_hash mismatch');
}
if (headerObject.alg === 'none') {
return Promise.resolve(token);
if (tokenSet.code && payload.c_hash !== undefined) {
assert(tokenHash(payload.c_hash, tokenSet.code), 'c_hash mismatch');
}
return (headerObject.alg.startsWith('HS') ? this.joseSecret() : this.issuer.key(headerObject))
if (header.alg === 'none') {
return Promise.resolve(tokenSet);
}
return (header.alg.startsWith('HS') ? this.joseSecret() : this.issuer.key(header))
.then(key => jose.JWS.createVerify(key).verify(idToken).catch(() => {
throw new Error('invalid signature');
}))
.then(() => token);
.then(() => tokenSet);
}
/**
* @name refresh
* @api public
*/
refresh(refreshToken) {

@@ -467,6 +487,10 @@ let token = refreshToken;

return this.decryptIdToken(tokenset, 'id_token')
.then(() => this.validateIdToken(tokenset, null, 'id_token', null));
.then(() => this.validateIdToken(tokenset, null, 'token', null));
});
}
/**
* @name userinfo
* @api public
*/
userinfo(accessToken, options) {

@@ -558,2 +582,6 @@ let token = accessToken;

/**
* @name grant
* @api public
*/
grant(body) {

@@ -565,2 +593,6 @@ assert(this.issuer.token_endpoint, 'issuer must be configured with token endpoint');

/**
* @name revoke
* @api public
*/
revoke(token, hint) {

@@ -575,2 +607,6 @@ assert(this.issuer.revocation_endpoint, 'issuer must be configured with revocation endpoint');

/**
* @name introspect
* @api public
*/
introspect(token, hint) {

@@ -586,2 +622,6 @@ assert(this.issuer.introspection_endpoint, 'issuer must be configured with introspection endpoint');

/* eslint-disable no-underscore-dangle */
/**
* @name fetchDistributedClaims
* @api public
*/
fetchDistributedClaims(claims, accessTokens) {

@@ -605,2 +645,6 @@ const distributedSources = _.pickBy(claims._claim_sources, def => !!def.endpoint);

/**
* @name unpackAggregatedClaims
* @api public
*/
unpackAggregatedClaims(claims) {

@@ -706,2 +750,6 @@ const aggregatedSources = _.pickBy(claims._claim_sources, def => !!def.JWT);

/**
* @name register
* @api public
*/
static register(properties, opts) {

@@ -747,2 +795,6 @@ const options = (() => {

/**
* @name fromUri
* @api public
*/
static fromUri(uri, token) {

@@ -756,2 +808,6 @@ return got(uri, this.issuer.httpOptions({

/**
* @name requestObject
* @api public
*/
requestObject(input, algorithms) {

@@ -758,0 +814,0 @@ assert.equal(typeof input, 'object', 'pass an object as the first argument');

@@ -41,2 +41,6 @@ 'use strict';

class Issuer {
/**
* @name constructor
* @api public
*/
constructor(metadata) {

@@ -123,2 +127,6 @@ const recognized = _.chain(metadata)

/**
* @name webfinger
* @api public
*/
static webfinger(input) {

@@ -152,2 +160,6 @@ const resource = webfingerNormalize(input);

/**
* @name discover
* @api public
*/
static discover(uri) {

@@ -171,2 +183,6 @@ uri = stripTrailingSlash(uri); // eslint-disable-line no-param-reassign

/**
* @name defaultHttpOptions
* @api public
*/
static get defaultHttpOptions() {

@@ -176,2 +192,6 @@ return defaultHttpOptions;

/**
* @name defaultHttpOptions=
* @api public
*/
static set defaultHttpOptions(value) {

@@ -178,0 +198,0 @@ defaultHttpOptions = _.merge({}, DEFAULT_HTTP_OPTIONS, value);

@@ -25,2 +25,6 @@ 'use strict';

/**
* @name constructor
* @api public
*/
function OpenIDConnectStrategy(options, verify) {

@@ -27,0 +31,0 @@ const opts = (() => {

{
"name": "openid-client",
"version": "1.5.3",
"version": "1.6.0",
"description": "OpenID Connect Relying Party (RP, Client) implementation for Node.js servers, supports passportjs",

@@ -5,0 +5,0 @@ "main": "lib/index.js",

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc