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 5.5.0 to 5.6.0

278

lib/client.js

@@ -7,2 +7,3 @@ const { inspect } = require('util');

const url = require('url');
const { URL, URLSearchParams } = require('url');

@@ -66,2 +67,8 @@ const jose = require('jose');

function getSearchParams(input) {
const parsed = url.parse(input);
if (!parsed.search) return {};
return querystring.parse(parsed.search.substring(1));
}
function verifyPresence(payload, jwt, prop) {

@@ -256,9 +263,17 @@ if (payload[prop] === undefined) {

assertIssuerConfiguration(this.issuer, 'authorization_endpoint');
const target = url.parse(this.issuer.authorization_endpoint, true);
target.search = null;
target.query = {
...target.query,
...authorizationParams.call(this, params),
};
return url.format(target);
const target = new URL(this.issuer.authorization_endpoint);
for (const [name, value] of Object.entries(authorizationParams.call(this, params))) {
if (Array.isArray(value)) {
target.searchParams.delete(name);
for (const member of value) {
target.searchParams.append(name, member);
}
} else {
target.searchParams.set(name, value);
}
}
// TODO: is the replace needed?
return target.href.replace('+', '%20');
}

@@ -303,6 +318,5 @@

const target = url.parse(this.issuer.end_session_endpoint, true);
target.search = null;
defaults(
target.query,
const target = url.parse(this.issuer.end_session_endpoint);
const query = defaults(
getSearchParams(this.issuer.end_session_endpoint),
params,

@@ -316,8 +330,11 @@ {

Object.entries(target.query).forEach(([key, value]) => {
Object.entries(query).forEach(([key, value]) => {
if (value === null || value === undefined) {
delete target.query[key];
delete query[key];
}
});
target.search = null;
target.query = query;
return url.format(target);

@@ -339,3 +356,3 @@ }

case 'GET':
return pickCb(url.parse(input.url, true).query);
return pickCb(getSearchParams(input.url));
case 'POST':

@@ -365,3 +382,3 @@ if (input.body === undefined) {

} else {
return pickCb(url.parse(input, true).query);
return pickCb(getSearchParams(input));
}

@@ -713,7 +730,11 @@ }

for (const { keyObject: key } of keystore.all({
...jose.decodeProtectedHeader(jwe),
const protectedHeader = jose.decodeProtectedHeader(jwe);
for (const key of keystore.all({
...protectedHeader,
use: 'enc',
})) {
plaintext = await jose.compactDecrypt(jwe, key).then(getPlaintext, () => {});
plaintext = await jose
.compactDecrypt(jwe, await key.keyObject(protectedHeader.alg))
.then(getPlaintext, () => {});
if (plaintext) break;

@@ -1027,3 +1048,9 @@ }

assert.equal(key.type, 'public');
keys = [{ keyObject: key }];
keys = [
{
keyObject() {
return key;
},
},
];
} catch (err) {

@@ -1053,3 +1080,3 @@ throw new RPError({

const verified = await jose
.compactVerify(jwt, key instanceof Uint8Array ? key : key.keyObject)
.compactVerify(jwt, key instanceof Uint8Array ? key : await key.keyObject(header.alg))
.catch(() => {});

@@ -1208,3 +1235,3 @@ if (verified) {

targetUrl = new url.URL(targetUrl || this.issuer.userinfo_endpoint);
targetUrl = new URL(targetUrl || this.issuer.userinfo_endpoint);

@@ -1214,3 +1241,3 @@ if (via === 'body') {

options.headers['Content-Type'] = 'application/x-www-form-urlencoded';
options.body = new url.URLSearchParams();
options.body = new URLSearchParams();
options.body.append(

@@ -1235,3 +1262,3 @@ 'access_token',

// POST && via header
options.body = new url.URLSearchParams();
options.body = new URLSearchParams();
options.headers['Content-Type'] = 'application/x-www-form-urlencoded';

@@ -1531,3 +1558,3 @@ Object.entries(params).forEach(([key, value]) => {

})
.sign(symmetric ? key : key.keyObject);
.sign(symmetric ? key : await key.keyObject(signingAlgorithm));
}

@@ -1556,3 +1583,3 @@

})
.encrypt(key instanceof Uint8Array ? key : key.keyObject);
.encrypt(key instanceof Uint8Array ? key : await key.keyObject(fields.alg));
}

@@ -1643,4 +1670,8 @@

privateKey = privateKeyInput;
} else if (privateKeyInput[Symbol.toStringTag] === 'CryptoKey') {
privateKey = privateKeyInput;
} else if (jose.cryptoRuntime === 'node:crypto') {
privateKey = crypto.createPrivateKey(privateKeyInput);
} else {
privateKey = crypto.createPrivateKey(privateKeyInput);
throw new TypeError('unrecognized crypto runtime');
}

@@ -1651,22 +1682,3 @@

}
let alg;
switch (privateKey.asymmetricKeyType) {
case 'ed25519':
case 'ed448':
alg = 'EdDSA';
break;
case 'ec':
alg = determineEcAlgorithm(privateKey, privateKeyInput);
break;
case 'rsa':
case rsaPssParams && 'rsa-pss':
alg = determineRsaAlgorithm(
privateKey,
privateKeyInput,
this.issuer.dpop_signing_alg_values_supported,
);
break;
default:
throw new TypeError('unsupported DPoP private key asymmetric key type');
}
let alg = determineDPoPAlgorithm.call(this, privateKey, privateKeyInput);

@@ -1694,77 +1706,134 @@ if (!alg) {

const RSPS = /^(?:RS|PS)(?:256|384|512)$/;
function determineRsaAlgorithm(privateKey, privateKeyInput, valuesSupported) {
if (
typeof privateKeyInput === 'object' &&
typeof privateKeyInput.key === 'object' &&
privateKeyInput.key.alg
) {
return privateKeyInput.key.alg;
function determineDPoPAlgorithmFromCryptoKey(cryptoKey) {
switch (cryptoKey.algorithm.name) {
case 'Ed25519':
case 'Ed448':
return 'EdDSA';
case 'ECDSA': {
switch (cryptoKey.algorithm.namedCurve) {
case 'P-256':
return 'ES256';
case 'P-384':
return 'ES384';
case 'P-521':
return 'ES512';
default:
break;
}
break;
}
case 'RSASSA-PKCS1-v1_5':
return `RS${cryptoKey.algorithm.hash.name.slice(4)}`;
case 'RSA-PSS':
return `PS${cryptoKey.algorithm.hash.name.slice(4)}`;
default:
throw new TypeError('unsupported DPoP private key');
}
}
if (Array.isArray(valuesSupported)) {
let candidates = valuesSupported.filter(RegExp.prototype.test.bind(RSPS));
if (privateKey.asymmetricKeyType === 'rsa-pss') {
candidates = candidates.filter((value) => value.startsWith('PS'));
let determineDPoPAlgorithm;
if (jose.cryptoRuntime === 'node:crypto') {
determineDPoPAlgorithm = function (privateKey, privateKeyInput) {
if (privateKeyInput[Symbol.toStringTag] === 'CryptoKey') {
return determineDPoPAlgorithmFromCryptoKey(privateKey);
}
return ['PS256', 'PS384', 'PS512', 'RS256', 'RS384', 'RS384'].find((preferred) =>
candidates.includes(preferred),
);
switch (privateKey.asymmetricKeyType) {
case 'ed25519':
case 'ed448':
return 'EdDSA';
case 'ec':
return determineEcAlgorithm(privateKey, privateKeyInput);
case 'rsa':
case rsaPssParams && 'rsa-pss':
return determineRsaAlgorithm(
privateKey,
privateKeyInput,
this.issuer.dpop_signing_alg_values_supported,
);
default:
throw new TypeError('unsupported DPoP private key');
}
};
const RSPS = /^(?:RS|PS)(?:256|384|512)$/;
function determineRsaAlgorithm(privateKey, privateKeyInput, valuesSupported) {
if (
typeof privateKeyInput === 'object' &&
privateKeyInput.format === 'jwk' &&
privateKeyInput.key &&
privateKeyInput.key.alg
) {
return privateKeyInput.key.alg;
}
if (Array.isArray(valuesSupported)) {
let candidates = valuesSupported.filter(RegExp.prototype.test.bind(RSPS));
if (privateKey.asymmetricKeyType === 'rsa-pss') {
candidates = candidates.filter((value) => value.startsWith('PS'));
}
return ['PS256', 'PS384', 'PS512', 'RS256', 'RS384', 'RS384'].find((preferred) =>
candidates.includes(preferred),
);
}
return 'PS256';
}
return 'PS256';
}
const p256 = Buffer.from([42, 134, 72, 206, 61, 3, 1, 7]);
const p384 = Buffer.from([43, 129, 4, 0, 34]);
const p521 = Buffer.from([43, 129, 4, 0, 35]);
const secp256k1 = Buffer.from([43, 129, 4, 0, 10]);
const p256 = Buffer.from([42, 134, 72, 206, 61, 3, 1, 7]);
const p384 = Buffer.from([43, 129, 4, 0, 34]);
const p521 = Buffer.from([43, 129, 4, 0, 35]);
const secp256k1 = Buffer.from([43, 129, 4, 0, 10]);
function determineEcAlgorithm(privateKey, privateKeyInput) {
// If input was a JWK
switch (
typeof privateKeyInput === 'object' &&
typeof privateKeyInput.key === 'object' &&
privateKeyInput.key.crv
) {
case 'P-256':
return 'ES256';
case 'secp256k1':
return 'ES256K';
case 'P-384':
return 'ES384';
case 'P-512':
return 'ES512';
default:
break;
}
function determineEcAlgorithm(privateKey, privateKeyInput) {
// If input was a JWK
switch (
typeof privateKeyInput === 'object' &&
typeof privateKeyInput.key === 'object' &&
privateKeyInput.key.crv
) {
case 'P-256':
const buf = privateKey.export({ format: 'der', type: 'pkcs8' });
const i = buf[1] < 128 ? 17 : 18;
const len = buf[i];
const curveOid = buf.slice(i + 1, i + 1 + len);
if (curveOid.equals(p256)) {
return 'ES256';
case 'secp256k1':
return 'ES256K';
case 'P-384':
}
if (curveOid.equals(p384)) {
return 'ES384';
case 'P-512':
}
if (curveOid.equals(p521)) {
return 'ES512';
default:
break;
}
}
const buf = privateKey.export({ format: 'der', type: 'pkcs8' });
const i = buf[1] < 128 ? 17 : 18;
const len = buf[i];
const curveOid = buf.slice(i + 1, i + 1 + len);
if (curveOid.equals(p256)) {
return 'ES256';
}
if (curveOid.equals(secp256k1)) {
return 'ES256K';
}
if (curveOid.equals(p384)) {
return 'ES384';
throw new TypeError('unsupported DPoP private key curve');
}
if (curveOid.equals(p521)) {
return 'ES512';
}
if (curveOid.equals(secp256k1)) {
return 'ES256K';
}
throw new TypeError('unsupported DPoP private key curve');
} else {
determineDPoPAlgorithm = determineDPoPAlgorithmFromCryptoKey;
}
const jwkCache = new WeakMap();
async function getJwk(privateKey, privateKeyInput) {
async function getJwk(keyObject, privateKeyInput) {
if (
jose.cryptoRuntime === 'node:crypto' &&
typeof privateKeyInput === 'object' &&
typeof privateKeyInput.key === 'object' &&
privateKeyInput.key.crv
privateKeyInput.format === 'jwk'
) {

@@ -1778,5 +1847,5 @@ return pick(privateKeyInput.key, 'kty', 'crv', 'x', 'y', 'e', 'n');

const jwk = pick(await jose.exportJWK(privateKey), 'kty', 'crv', 'x', 'y', 'e', 'n');
const jwk = pick(await jose.exportJWK(keyObject), 'kty', 'crv', 'x', 'y', 'e', 'n');
if (isKeyObject(privateKeyInput)) {
if (isKeyObject(privateKeyInput) || jose.cryptoRuntime === 'WebCryptoAPI') {
jwkCache.set(privateKeyInput, jwk);

@@ -1798,2 +1867,3 @@ }

};
module.exports.BaseClient = BaseClient;

@@ -73,3 +73,3 @@ const jose = require('jose');

.setProtectedHeader({ alg, kid: key.jwk && key.jwk.kid })
.sign(key.keyObject);
.sign(await key.keyObject(alg));
}

@@ -76,0 +76,0 @@

@@ -5,3 +5,2 @@ const jose = require('jose');

const isPlainObject = require('./is_plain_object');
const isKeyObject = require('./is_key_object');

@@ -55,3 +54,3 @@ const internal = Symbol();

// Ed25519, Ed448, and secp256k1 always have "alg"
// OKP always has use
// OKP always has "use"
if (alg) {

@@ -70,3 +69,16 @@ return new Set([alg]);

if (use === 'sig' || use === undefined) {
algs = algs.concat([`ES${crv.slice(-3)}`.replace('21', '12')]);
switch (crv) {
case 'P-256':
case 'P-384':
algs = algs.concat([`ES${crv.slice(-3)}`.replace('21', '12')]);
break;
case 'P-521':
algs = algs.concat(['ES512']);
break;
case 'secp256k1':
if (jose.cryptoRuntime === 'node:crypto') {
algs = algs.concat(['ES256K']);
}
break;
}
}

@@ -83,3 +95,6 @@

if (use === 'enc' || use === undefined) {
algs = algs.concat(['RSA-OAEP', 'RSA-OAEP-256', 'RSA-OAEP-384', 'RSA-OAEP-512', 'RSA1_5']);
algs = algs.concat(['RSA-OAEP', 'RSA-OAEP-256', 'RSA-OAEP-384', 'RSA-OAEP-512']);
if (jose.cryptoRuntime === 'node:crypto') {
algs = algs.concat(['RSA1_5']);
}
}

@@ -232,32 +247,21 @@

const keyObject = await jose.importJWK(jwk, alg || fauxAlg(jwk.kty)).catch(() => {});
if (!keyObject) continue;
if (keyObject instanceof Uint8Array || keyObject.type === 'secret') {
if (onlyPrivate) {
throw new Error('jwks must only contain private keys');
}
continue;
}
if (!isKeyObject(keyObject)) {
throw new Error('what?!');
}
if (onlyPrivate && keyObject.type !== 'private') {
if (onlyPrivate && (jwk.kty === 'oct' || !jwk.d)) {
throw new Error('jwks must only contain private keys');
}
if (onlyPublic && keyObject.type !== 'public') {
if (onlyPublic && (jwk.d || jwk.k)) {
continue;
}
if (kty === 'RSA' && keyObject.asymmetricKeySize < 2048) {
continue;
}
keys.push({
jwk: { ...jwk, alg, use },
keyObject,
async keyObject(alg) {
if (this[alg]) {
return this[alg];
}
const keyObject = await jose.importJWK(this.jwk, alg);
this[alg] = keyObject;
return keyObject;
},
get algorithms() {

@@ -264,0 +268,0 @@ Object.defineProperty(this, 'algorithms', {

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

@@ -48,3 +48,3 @@ "keywords": [

"dependencies": {
"jose": "^4.14.4",
"jose": "^4.15.1",
"lru-cache": "^6.0.0",

@@ -55,13 +55,12 @@ "object-hash": "^2.2.0",

"devDependencies": {
"@types/node": "^16.18.31",
"@types/passport": "^1.0.12",
"@types/node": "^16.18.55",
"@types/passport": "^1.0.13",
"base64url": "^3.0.1",
"chai": "^4.3.7",
"jose2": "npm:jose@^2.0.6",
"chai": "^4.3.10",
"mocha": "^10.2.0",
"nock": "^13.3.1",
"nock": "^13.3.3",
"prettier": "^2.8.8",
"readable-mock-req": "^0.2.2",
"sinon": "^9.2.4",
"timekeeper": "^2.2.0"
"timekeeper": "^2.3.1"
},

@@ -68,0 +67,0 @@ "standard-version": {

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