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 3.15.10 to 4.0.0

lib/index.mjs

41

CHANGELOG.md

@@ -5,2 +5,43 @@ # Changelog

## [4.0.0](https://github.com/panva/node-openid-client/compare/v3.15.10...v4.0.0) (2020-09-09)
### ⚠ BREAKING CHANGES
* the deprecated `issuer.key()` method was removed
* due to added ESM module support Node.js version with
ESM implementation bugs are no longer supported, this only affects early
v13.x versions. The resulting Node.js semver range is
`^10.19.0 || >=12.0.0 < 13 || >=13.7.0` (also taking into account the
`got` dependency update)
* upgraded got http request library dependency from
`v9.x` to `v11.x`. If you override some of the http request options
you will most certainly have to accomodate them.
* Signed Request Object "typ" changed from `JWT` to
`oauth.authz.req+jwt`
* Encrypted Request Object "cty" changed from `JWT` to
`oauth.authz.req+jwt`
* PKCE is now used by default in the passport strategy
* `client.userinfo()` `verb` parameter was renamed to
`method`
* the deprecated `client.resource()` method was removed
### Features
* added support for ESM (ECMAScript modules) ([3ac37e8](https://github.com/panva/node-openid-client/commit/3ac37e80d66d47e9814972ed86d1323b9ee96b79))
* passport strategy will now use PKCE by default where applicable ([56f9fe7](https://github.com/panva/node-openid-client/commit/56f9fe7171ccc1bec6427d4f9bc45e419150ab4d))
### Bug Fixes
* request object type changed from 'JWT' to 'oauth.authz.req+jwt' ([641a42f](https://github.com/panva/node-openid-client/commit/641a42fdd3097289085340afab652e4b8b9f571c))
### Refactor
* remove deprecated `client.resource()` ([c0ec865](https://github.com/panva/node-openid-client/commit/c0ec8652673c7b276a7c71eb2d730eb3feb22eeb))
* remove deprecated `issuer.key()` ([5cd1ecf](https://github.com/panva/node-openid-client/commit/5cd1ecfced358c7a685d9dc29aa451a9ef13b770))
* rename `client.userinfo()` `verb` parameter to `method` ([4cb21a4](https://github.com/panva/node-openid-client/commit/4cb21a4c2aef6421fe7a0f67d45baf209989cdd4))
* upgrade got from v9.x to v11.x ([c72b5e8](https://github.com/panva/node-openid-client/commit/c72b5e812f6a94a92e008facefa72c366728d4a5))
## [3.15.10](https://github.com/panva/node-openid-client/compare/v3.15.9...v3.15.10) (2020-09-02)

@@ -7,0 +48,0 @@

157

lib/client.js
/* eslint-disable max-classes-per-file */
const { inspect, deprecate } = require('util');
const { inspect } = require('util');
const stdhttp = require('http');

@@ -33,4 +33,2 @@ const crypto = require('crypto');

const { deep: defaultsDeep } = defaults;
function pickCb(input) {

@@ -628,12 +626,2 @@ return pick(input, ...CALLBACK_PROPERTIES);

/**
* @name validateJARM
* @api private
*/
async validateJARM(response) {
const expectedAlg = this.authorization_signed_response_alg;
const { payload } = await this.validateJWT(response, expectedAlg, ['iss', 'exp', 'aud']);
return pickCb(payload);
}
/**
* @name decryptJWTUserinfo

@@ -972,3 +960,6 @@ * @api private

try {
return jose.JWS.verify(jwt, key, { complete: true });
return {
...jose.JWS.verify(jwt, key, { complete: true }),
payload,
};
} catch (err) {

@@ -1050,3 +1041,3 @@ throw new RPError({

...requestOpts,
encoding: null,
responseType: 'buffer',
method,

@@ -1062,9 +1053,8 @@ url: resourceUrl,

async userinfo(accessToken, {
verb = 'GET', via = 'header', tokenType, params,
method = 'GET', via = 'header', tokenType, params,
} = {}) {
// TODO: in v4.x remove verb in favour of method
assertIssuerConfiguration(this.issuer, 'userinfo_endpoint');
const options = {
tokenType,
method: String(verb).toUpperCase(),
method: String(method).toUpperCase(),
};

@@ -1082,4 +1072,3 @@

const jwt = !!(this.userinfo_signed_response_alg
|| this.userinfo_encrypted_response_alg);
const jwt = !!(this.userinfo_signed_response_alg || this.userinfo_encrypted_response_alg);

@@ -1167,7 +1156,3 @@ if (jwt) {

} catch (error) {
const parseError = new ParseError(
error, response.statusCode, response.request.gotOptions, response.body,
);
Object.defineProperty(parseError, 'response', { value: response });
throw parseError;
throw new ParseError(error, response);
}

@@ -1252,5 +1237,4 @@ }

{
form: true,
body,
json: true,
form: body,
responseType: 'json',
},

@@ -1283,5 +1267,4 @@ { clientAssertionPayload },

{
form: true,
body,
json: true,
responseType: 'json',
form: body,
},

@@ -1311,6 +1294,6 @@ { clientAssertionPayload, endpointAuthMethod: 'token' },

const body = { ...revokeBody, token };
const form = { ...revokeBody, token };
if (hint) {
body.token_type_hint = hint;
form.token_type_hint = hint;
}

@@ -1321,4 +1304,3 @@

'revocation', {
body,
form: true,
form,
}, { clientAssertionPayload },

@@ -1339,5 +1321,5 @@ );

const body = { ...introspectBody, token };
const form = { ...introspectBody, token };
if (hint) {
body.token_type_hint = hint;
form.token_type_hint = hint;
}

@@ -1348,3 +1330,3 @@

'introspection',
{ body, form: true, json: true },
{ form, responseType: 'json' },
{ clientAssertionPayload },

@@ -1462,4 +1444,4 @@ );

} : undefined,
json: true,
body: metadata,
responseType: 'json',
json: metadata,
url: this.issuer.registration_endpoint,

@@ -1493,3 +1475,3 @@ method: 'POST',

url: registrationClientUri,
json: true,
responseType: 'json',
headers: { Authorization: authorizationHeaderValue(registrationAccessToken) },

@@ -1520,3 +1502,3 @@ });

const header = { alg: signingAlgorithm, typ: 'JWT' };
const header = { alg: signingAlgorithm, typ: 'oauth.authz.req+jwt' };
const payload = JSON.stringify(defaults({}, requestObject, {

@@ -1563,3 +1545,3 @@ iss: this.client_id,

const fields = { alg: eKeyManagement, enc: eContentEncryption, cty: 'JWT' };
const fields = { alg: eKeyManagement, enc: eContentEncryption, cty: 'oauth.authz.req+jwt' };

@@ -1609,68 +1591,29 @@ if (fields.alg.match(/^(RSA|ECDH)/)) {

// TODO: remove in 4.x
BaseClient.prototype.resource = deprecate(
/* istanbul ignore next */
async function resource(resourceUrl, accessToken, options) {
let token = accessToken;
const opts = {
verb: 'GET',
via: 'header',
...options,
};
/**
* @name validateJARM
* @api private
*/
async function validateJARM(response) {
const expectedAlg = this.authorization_signed_response_alg;
const { payload } = await this.validateJWT(response, expectedAlg, ['iss', 'exp', 'aud']);
return pickCb(payload);
}
if (token instanceof TokenSet) {
if (!token.access_token) {
throw new TypeError('access_token not present in TokenSet');
}
opts.tokenType = opts.tokenType || token.token_type;
token = token.access_token;
}
Object.defineProperty(BaseClient.prototype, 'validateJARM', {
enumerable: true,
configurable: true,
value(...args) {
process.emitWarning(
"The JARM API implements an OIDF implementer's draft. Breaking draft implementations are included as minor versions of the openid-client library, therefore, the ~ semver operator should be used and close attention be payed to library changelog as well as the drafts themselves.",
'DraftWarning',
);
Object.defineProperty(BaseClient.prototype, 'validateJARM', {
enumerable: true,
configurable: true,
value: validateJARM,
});
return this.validateJARM(...args);
},
});
const verb = String(opts.verb).toUpperCase();
let requestOpts;
switch (opts.via) {
case 'query':
if (verb !== 'GET') {
throw new TypeError('resource servers should only parse query strings for GET requests');
}
requestOpts = { query: { access_token: token } };
break;
case 'body':
if (verb !== 'POST') {
throw new TypeError('can only send body on POST');
}
requestOpts = { form: true, body: { access_token: token } };
break;
default:
requestOpts = {
headers: {
Authorization: authorizationHeaderValue(token, opts.tokenType),
},
};
}
if (opts.params) {
if (verb === 'POST') {
defaultsDeep(requestOpts, { body: opts.params });
} else {
defaultsDeep(requestOpts, { query: opts.params });
}
}
if (opts.headers) {
defaultsDeep(requestOpts, { headers: opts.headers });
}
const mTLS = !!this.tls_client_certificate_bound_access_tokens;
return request.call(this, {
...requestOpts,
encoding: null,
method: verb,
url: resourceUrl,
}, { mTLS });
}, 'client.resource() is deprecated, use client.requestResource() instead, see docs for API details',
);
module.exports.BaseClient = BaseClient;

@@ -45,4 +45,3 @@ /* eslint-disable camelcase */

{
form: true,
body: {
form: {
...instance(this).exchangeBody,

@@ -52,3 +51,3 @@ grant_type: 'urn:ietf:params:oauth:grant-type:device_code',

},
json: true,
responseType: 'json',
},

@@ -55,0 +54,0 @@ { clientAssertionPayload: instance(this).clientAssertionPayload },

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

case 'none':
return { body: { client_id: this.client_id } };
return { form: { client_id: this.client_id } };
case 'client_secret_post':

@@ -65,3 +65,3 @@ if (!this.client_secret) {

}
return { body: { client_id: this.client_id, client_secret: this.client_secret } };
return { form: { client_id: this.client_id, client_secret: this.client_secret } };
case 'private_key_jwt':

@@ -76,3 +76,3 @@ case 'client_secret_jwt': {

sub: this.client_id,
aud: this.issuer[`${endpoint}_endpoint`], // TODO: in v4.x pass the issuer instead (for now clientAssertionPayload can be used for that)
aud: this.issuer[`${endpoint}_endpoint`] || this.issuer.issuer,
...clientAssertionPayload,

@@ -82,3 +82,3 @@ });

return {
body: {
form: {
client_id: this.client_id,

@@ -132,3 +132,3 @@ client_assertion: assertion,

const auth = await authFor.call(this, endpointAuthMethod, { clientAssertionPayload });
const requestOpts = merge(opts, auth, { form: true });
const requestOpts = merge(opts, auth);

@@ -145,6 +145,6 @@ const mTLS = this[`${endpointAuthMethod}_endpoint_auth_method`].includes('tls_client_auth')

if ('body' in requestOpts) {
for (const [key, value] of Object.entries(requestOpts.body)) { // eslint-disable-line no-restricted-syntax, max-len
if ('form' in requestOpts) {
for (const [key, value] of Object.entries(requestOpts.form)) { // eslint-disable-line no-restricted-syntax, max-len
if (typeof value === 'undefined') {
delete requestOpts.body[key];
delete requestOpts.form[key];
}

@@ -151,0 +151,0 @@ }

@@ -21,3 +21,3 @@ const Got = require('got');

retry: 0,
timeout: 2500,
timeout: 3500,
throwHttpErrors: false,

@@ -37,3 +37,9 @@ });

if (mTLS && (!opts.key || !opts.cert)) {
if (
mTLS
&& (
(!opts.key || !opts.cert)
&& (!opts.https || !opts.https.key || !opts.https.certificate)
)
) {
throw new TypeError('mutual-TLS certificate and key not set');

@@ -40,0 +46,0 @@ }

/* eslint-disable max-classes-per-file */
const { inspect, deprecate } = require('util');
const { inspect } = require('util');
const url = require('url');

@@ -70,3 +70,16 @@

Object.defineProperty(this, 'FAPIClient', {
value: class FAPIClient extends this.Client {},
enumerable: true,
configurable: true,
get() {
process.emitWarning(
"The FAPI API implements an OIDF implementer's draft. Breaking draft implementations are included as minor versions of the openid-client library, therefore, the ~ semver operator should be used and close attention be payed to library changelog as well as the drafts themselves.",
'DraftWarning',
);
Object.defineProperty(this, 'FAPIClient', {
enumerable: true,
configurable: true,
value: class FAPIClient extends this.Client {},
});
return this.FAPIClient;
},
});

@@ -89,3 +102,3 @@ }

method: 'GET',
json: true,
responseType: 'json',
url: this.jwks_uri,

@@ -173,4 +186,4 @@ });

url: webfingerUrl,
json: true,
query: { resource, rel: REL },
responseType: 'json',
searchParams: { resource, rel: REL },
followRedirect: true,

@@ -220,3 +233,3 @@ });

method: 'GET',
json: true,
responseType: 'json',
url: uri,

@@ -250,3 +263,3 @@ });

method: 'GET',
json: true,
responseType: 'json',
url: wellKnownUri,

@@ -276,46 +289,2 @@ });

/**
* @name key
* @api private
*/
Issuer.prototype.key = deprecate(async function key({
kid, kty, alg, use, key_ops: ops,
}, allowMulti = false) {
const cache = instance(this).get('cache');
const def = {
kid, kty, alg, use, key_ops: ops,
};
const defHash = objectHash(def, {
algorithm: 'sha256',
ignoreUnknown: true,
unorderedArrays: true,
unorderedSets: true,
});
// refresh keystore on every unknown key but also only upto once every minute
const freshJwksUri = cache.get(defHash) || cache.get('throttle');
const keystore = await this.keystore(!freshJwksUri);
const keys = keystore.all(def);
if (keys.length === 0) {
throw new RPError({
printf: ["no valid key found in issuer's jwks_uri for key parameters %j", def],
jwks: keystore,
});
}
if (!allowMulti) {
if (keys.length !== 1) {
throw new RPError({
printf: ["multiple matching keys found in issuer's jwks_uri for key parameters %j, kid must be provided in this case", def],
jwks: keystore,
});
}
cache.set(defHash, true);
}
return keys[0];
}, 'issuer.key is not only a private API, it is also deprecated');
module.exports = Issuer;

@@ -32,3 +32,3 @@ /* eslint-disable no-underscore-dangle */

sessionKey,
usePKCE = false,
usePKCE,
} = {}, verify) {

@@ -55,13 +55,18 @@ if (!(client instanceof BaseClient)) {

if (this._usePKCE === true) {
const supportedMethods = this._issuer.code_challenge_methods_supported;
if (!Array.isArray(supportedMethods)) {
throw new TypeError('code_challenge_methods_supported is not properly set on issuer');
}
if (supportedMethods.includes('S256')) {
if (!this._params.response_type) this._params.response_type = resolveResponseType.call(client);
if (!this._params.redirect_uri) this._params.redirect_uri = resolveRedirectUri.call(client);
if (!this._params.scope) this._params.scope = 'openid';
if (this._usePKCE === true || (typeof this._usePKCE === 'undefined' && this._params.response_type.includes('code'))) {
const supportedMethods = Array.isArray(this._issuer.code_challenge_methods_supported)
? this._issuer.code_challenge_methods_supported : false;
if (supportedMethods && supportedMethods.includes('S256')) {
this._usePKCE = 'S256';
} else if (supportedMethods.includes('plain')) {
} else if (supportedMethods && supportedMethods.includes('plain')) {
this._usePKCE = 'plain';
} else if (supportedMethods) {
throw new TypeError('neither code_challenge_method supported by the client is supported by the issuer');
} else {
throw new TypeError('neither supported code_challenge_method is supported by the issuer');
this._usePKCE = 'S256';
}

@@ -73,6 +78,2 @@ } else if (typeof this._usePKCE === 'string' && !['plain', 'S256'].includes(this._usePKCE)) {

this.name = url.parse(client.issuer.issuer).hostname;
if (!this._params.response_type) this._params.response_type = resolveResponseType.call(client);
if (!this._params.redirect_uri) this._params.redirect_uri = resolveRedirectUri.call(client);
if (!this._params.scope) this._params.scope = 'openid';
}

@@ -79,0 +80,0 @@

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

@@ -27,4 +27,13 @@ "keywords": [

"repository": "panva/node-openid-client",
"funding": {
"url": "https://github.com/sponsors/panva"
},
"license": "MIT",
"author": "Filip Skokan <panva.ip@gmail.com>",
"exports": {
"import": "./lib/index.mjs",
"require": "./lib/index.js"
},
"main": "lib/index.js",
"types": "types/index.d.ts",
"files": [

@@ -34,19 +43,29 @@ "lib",

],
"funding": {
"url": "https://github.com/sponsors/panva"
},
"main": "lib/index.js",
"types": "types/index.d.ts",
"scripts": {
"coverage": "nyc mocha test/**/*.test.js",
"lint": "eslint lib test",
"lint-fix": "eslint lib test --fix",
"lint-ts": "npx typescript@~3.6.0 --build types",
"lint-fix": "eslint lib test --fix",
"test": "mocha test/**/*.test.js"
},
"husky": {
"hooks": {
"commit-msg": "commitlint -E HUSKY_GIT_PARAMS"
}
},
"commitlint": {
"extends": [
"@commitlint/config-conventional"
]
},
"nyc": {
"reporter": [
"lcov",
"text-summary"
]
},
"dependencies": {
"@types/got": "^9.6.9",
"base64url": "^3.0.1",
"got": "^9.6.0",
"jose": "^1.27.1",
"got": "^11.5.2",
"jose": "^2.0.0",
"lru-cache": "^6.0.0",

@@ -75,25 +94,44 @@ "make-error": "^1.3.6",

"engines": {
"node": "^10.13.0 || >=12.0.0"
"node": "^10.19.0 || >=12.0.0 < 13 || >=13.7.0 < 14 || >= 14.2.0"
},
"commitlint": {
"extends": [
"@commitlint/config-conventional"
]
},
"husky": {
"hooks": {
"commit-msg": "commitlint -E HUSKY_GIT_PARAMS"
}
},
"nyc": {
"reporter": [
"lcov",
"text-summary"
]
},
"standard-version": {
"scripts": {
"postchangelog": "sed -i '' -e 's/### \\[/## [/g' CHANGELOG.md"
}
},
"types": [
{
"type": "feat",
"section": "Features"
},
{
"type": "fix",
"section": "Bug Fixes"
},
{
"type": "chore",
"hidden": true
},
{
"type": "docs",
"hidden": true
},
{
"type": "style",
"hidden": true
},
{
"type": "refactor",
"section": "Refactor",
"hidden": true
},
{
"type": "perf",
"hidden": true
},
{
"type": "test",
"hidden": true
}
]
}
}

@@ -47,3 +47,9 @@ # openid-client

- RP-Initiated Logout
- [Financial-grade API - Part 2: Read and Write API Security Profile (FAPI) - ID2][feature-fapi]
- [JWT Secured Authorization Response Mode for OAuth 2.0 (JARM) - ID1][feature-jarm]
Updates to draft specifications (JARM, and FAPI) are released as MINOR library versions,
if you utilize these specification implementations consider using the tilde `~` operator in your
package.json since breaking changes may be introduced as part of these version updates.
## Certification

@@ -85,3 +91,3 @@ [<img width="184" height="96" align="right" src="https://cdn.jsdelivr.net/gh/panva/node-openid-client@38cf016b0837e6d4116de3780b28d222d5780bc9/OpenID_Certified.png" alt="OpenID Certification">][openid-certified-link]

Node.js version **>=12.0.0** is recommended, but **^10.13.0** lts/dubnium is also supported.
Node.js version **>=12.0.0** is recommended, but **^10.19.0** lts/dubnium is also supported.

@@ -265,3 +271,3 @@ ```console

It is **only built for ^10.13.0 || >=12.0.0 Node.js** environment - including openid-client in
It is **only built for ^10.19.0 || >=12.0.0 Node.js** environment - including openid-client in
browser-environment targeted projects is not supported and may result in unexpected results.

@@ -302,2 +308,4 @@

[feature-rp-logout]: https://openid.net/specs/openid-connect-session-1_0.html#RPLogout
[feature-jarm]: https://openid.net/specs/openid-financial-api-jarm-ID1.html
[feature-fapi]: https://openid.net/specs/openid-financial-api-part-2-ID2.html
[openid-certified-link]: https://openid.net/certification/

@@ -304,0 +312,0 @@ [passport-url]: http://passportjs.org

@@ -8,11 +8,9 @@ /// <reference types="node" />

import * as http from 'http';
import * as https from 'https';
import * as http2 from 'http2';
import * as tls from 'tls';
import { GotOptions, GotPromise } from 'got';
import { Options as GotOptions, CancelableRequest, Response } from 'got';
import { URL } from 'url';
import { JWKS, JSONWebKeySet } from 'jose';
export type HttpOptions = GotOptions<string | null>;
export type HttpOptions = GotOptions;
export type RetryFunction = (retry: number, error: Error) => number;

@@ -412,10 +410,5 @@ export type CustomHttpOptionsProvider = (options: HttpOptions) => HttpOptions;

*/
userinfo(accessToken: TokenSet | string, options?: { verb?: 'GET' | 'POST', via?: 'header' | 'body' | 'query', tokenType?: string, params?: object }): Promise<UserinfoResponse>;
userinfo(accessToken: TokenSet | string, options?: { method?: 'GET' | 'POST', via?: 'header' | 'body' | 'query', tokenType?: string, params?: object }): Promise<UserinfoResponse>;
/**
* @deprecated in favor of client.requestResource
*/
resource(resourceUrl: string, accessToken: TokenSet | string, options?: { headers?: object, verb?: 'GET' | 'POST', via?: 'header' | 'body' | 'query', tokenType?: string }): GotPromise<Buffer>;
/**
* Fetches an arbitrary resource with the provided Access Token in an Authorization header.

@@ -430,6 +423,6 @@ *

headers?: object
body: string | Buffer
body?: string | Buffer
method?: 'GET' | 'POST' | 'PUT' | 'HEAD' | 'DELETE' | 'OPTIONS' | 'TRACE'
tokenType?: string
}): GotPromise<Buffer>;
}): CancelableRequest<Response<Buffer>>;

@@ -436,0 +429,0 @@ /**

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