From 83376ac017704c57aee7d1b7e5397bfb549cb970 Mon Sep 17 00:00:00 2001 From: Filip Skokan Date: Tue, 19 Oct 2021 15:03:49 +0200 Subject: [PATCH] refactor: only use the native http(s) client BREAKING CHANGE: HTTP(S) request customization now only recognizes the following options 'agent', 'ca', 'cert', 'crl', 'headers', 'key', 'lookup', 'passphrase', 'pfx', and 'timeout'. These are standard node http/https module request options, got-library specific options such as 'followRedirect', 'retry', or 'throwHttpErrors' are no longer recognized. BREAKING CHANGE: The arguments inside individual HTTP request customization changed, first argument is now an instance of [URL](https://nodejs.org/api/url.html#class-url), the http request options object is passed in as a second argument. BREAKING CHANGE: The `response` property attached to some RPError or OPError instances is now an instance of [http.IncomingMessage](https://nodejs.org/api/http.html#class-httpincomingmessage). Its body is available on its `body` property as either JSON if it could be parsed, or a Buffer if it failed to pass as JSON. --- README.md | 4 - docs/README.md | 62 +++------ lib/client.js | 10 +- lib/helpers/is_absolute_url.js | 12 -- lib/helpers/process_response.js | 2 +- lib/helpers/request.js | 167 +++++++++++++++++++++---- lib/issuer.js | 7 +- package.json | 7 +- test/client/client_instance.test.js | 6 +- test/client/discover_client.test.js | 8 +- test/client/dpop.test.js | 2 +- test/client/mtls.test.js | 6 +- test/client/register_client.test.js | 8 +- test/issuer/discover_issuer.test.js | 8 +- test/issuer/discover_webfinger.test.js | 5 +- test/issuer/issuer_instance.test.js | 15 +-- types/index.d.ts | 6 +- types/openid-client-tests.ts | 16 +-- 18 files changed, 205 insertions(+), 146 deletions(-) delete mode 100644 lib/helpers/is_absolute_url.js diff --git a/README.md b/README.md index 3cf71c7c..78ed84de 100644 --- a/README.md +++ b/README.md @@ -277,10 +277,6 @@ See [Client Authentication Methods (docs)][documentation-methods]. See [Customizing (docs)](https://github.com/panva/node-openid-client/blob/master/docs/README.md#customizing). -#### How can I debug the requests and responses? - -See [Customizing (docs)](https://github.com/panva/node-openid-client/blob/master/docs/README.md#customizing). - [openid-connect]: https://openid.net/connect/ [feature-core]: https://openid.net/specs/openid-connect-core-1_0.html diff --git a/docs/README.md b/docs/README.md index 86571895..15279a5a 100644 --- a/docs/README.md +++ b/docs/README.md @@ -659,65 +659,41 @@ This function will then be called before executing each and every request on the const { custom } = require('openid-client'); // you can also set this on Issuer constructor, Issuer instance, or Client constructor -client[custom.http_options] = function (options) { +client[custom.http_options] = function (url, options) { + // console.log(url); // console.log(options); - options.timeout = 5000; - return options; + return { timeout: 5000 }; } ``` -This is meant to change request options on per-request basis should there be a specific IdP quirk -you need to work around, e.g. adding custom headers or body payload parameters. +The following options can be provided `agent`, `ca`, `cert`, `crl`, `headers`, `key`, `lookup`, `passphrase`, +`pfx`, `timeout`. These are all relayed to https://nodejs.org/api/https.html#httpsrequesturl-options-callback
Example (Click to expand) providing mutual-TLS client certificate and key ```js const { custom } = require('openid-client'); -client[custom.http_options] = function (options) { - // see https://github.com/sindresorhus/got/tree/v11.8.0#advanced-https-api - options.https = options.https || {}; - options.https.certificate = certificate; // | | | - options.https.key = key; // | | | | - // custom CA - // options.https.ca = ca; // | | | - - // use with .p12/.pfx files - // options.https.pfx = pfx; // | | | | - // options.https.passphrase = passphrase; // - - // use HTTP(S)_PROXY - // https://github.com/sindresorhus/got/tree/v11.8.0#agent - // options.agent = agent; - - return options; -} -``` -
- -
- Example (Click to expand) Other options - -```js -const { custom } = require('openid-client'); -client[custom.http_options] = function (options) { - // https://github.com/sindresorhus/got/tree/v11.8.0#headers - // options.headers = Object.assign(options.headers, { 'custom': 'foo' }); +client[custom.http_options] = function (url, options) { + // https://nodejs.org/api/tls.html#tlscreatesecurecontextoptions + const result = {}; - // https://github.com/sindresorhus/got/tree/v11.8.0#timeout - // options.timeout = timeout; + result.cert = cert; // | | | + result.key = key; // | | | | - // https://github.com/sindresorhus/got/tree/v11.8.0#retry - // options.retry = retry; + // custom CA + // result.ca = ca; // | | | - // https://github.com/sindresorhus/got/tree/v11.8.0#followredirect - // options.followRedirect = false; + // use with .p12/.pfx files + // result.pfx = pfx; // | | | | + // result.passphrase = passphrase; // // use HTTP(S)_PROXY - // https://github.com/sindresorhus/got/tree/v11.8.0#agent - // options.agent = agent; + // https://nodejs.org/api/http.html#httprequesturl-options-callback + // e.g. using https://www.npmjs.com/package/proxy-agent + // result.agent = agent; - return options; + return result; } ```
diff --git a/lib/client.js b/lib/client.js index 69ca0f6f..5a5a7333 100644 --- a/lib/client.js +++ b/lib/client.js @@ -7,7 +7,6 @@ const { strict: assert } = require('assert'); const querystring = require('querystring'); const url = require('url'); -const { ParseError } = require('got'); const jose = require('jose'); const tokenHash = require('oidc-token-hash'); @@ -95,6 +94,10 @@ function authorizationParams(params) { async function claimJWT(label, jwt) { try { + if (Buffer.isBuffer(jwt)) { + // eslint-disable-next-line no-param-reassign + jwt = jwt.toString('ascii'); + } const { header, payload } = jose.JWT.decode(jwt, { complete: true }); const { iss } = payload; @@ -1160,8 +1163,9 @@ module.exports = (issuer, aadIssValidation = false) => class Client extends Base } else { try { parsed = JSON.parse(response.body); - } catch (error) { - throw new ParseError(error, response); + } catch (err) { + Object.defineProperty(err, 'response', response); + throw err; } } diff --git a/lib/helpers/is_absolute_url.js b/lib/helpers/is_absolute_url.js deleted file mode 100644 index 4bfbe440..00000000 --- a/lib/helpers/is_absolute_url.js +++ /dev/null @@ -1,12 +0,0 @@ -const url = require('url'); -const { strict: assert } = require('assert'); - -module.exports = (target) => { - try { - const { protocol } = new url.URL(target); - assert(protocol.match(/^(https?:)$/)); - return true; - } catch (err) { - throw new TypeError('only valid absolute URLs can be requested'); - } -}; diff --git a/lib/helpers/process_response.js b/lib/helpers/process_response.js index 989f82ad..923aeb81 100644 --- a/lib/helpers/process_response.js +++ b/lib/helpers/process_response.js @@ -29,7 +29,7 @@ const isStandardBodyError = (response) => { jsonbody = response.body; } result = typeof jsonbody.error === 'string' && jsonbody.error.length; - if (result) response.body = jsonbody; + if (result) Object.defineProperty(response, 'body', { value: jsonbody, configurable: true }); } catch (err) {} return result; diff --git a/lib/helpers/request.js b/lib/helpers/request.js index 44b876d5..48e0f9af 100644 --- a/lib/helpers/request.js +++ b/lib/helpers/request.js @@ -1,30 +1,57 @@ -const Got = require('got'); +const assert = require('assert'); +const querystring = require('querystring'); +const http = require('http'); +const https = require('https'); +const { once } = require('events'); + +const CacheableLookup = require('cacheable-lookup'); +const QuickLRU = require('quick-lru'); const pkg = require('../../package.json'); +const { RPError } = require('../errors'); +const pick = require('./pick'); const { deep: defaultsDeep } = require('./defaults'); -const isAbsoluteUrl = require('./is_absolute_url'); const { HTTP_OPTIONS } = require('./consts'); let DEFAULT_HTTP_OPTIONS; -let got; -const setDefaults = (options) => { - DEFAULT_HTTP_OPTIONS = defaultsDeep({}, options, DEFAULT_HTTP_OPTIONS); - got = Got.extend(DEFAULT_HTTP_OPTIONS); +const cacheable = new CacheableLookup({ + cache: new QuickLRU({ maxSize: 1000 }), +}); +const allowed = [ + 'agent', + 'ca', + 'cert', + 'crl', + 'headers', + 'key', + 'lookup', + 'passphrase', + 'pfx', + 'timeout', +]; + +const setDefaults = (props, options) => { + // eslint-disable-next-line max-len + DEFAULT_HTTP_OPTIONS = defaultsDeep({}, props.length ? pick(options, ...props) : options, DEFAULT_HTTP_OPTIONS); }; -setDefaults({ - followRedirect: false, +setDefaults([], { headers: { 'User-Agent': `${pkg.name}/${pkg.version} (${pkg.homepage})` }, - retry: 0, timeout: 3500, - throwHttpErrors: false, + lookup: cacheable.lookup, }); module.exports = async function request(options, { accessToken, mTLS = false, DPoP } = {}) { - const { url } = options; - isAbsoluteUrl(url); + let url; + try { + url = new URL(options.url); + delete options.url; + assert(/^(https?:)$/.test(url.protocol)); + } catch (err) { + throw new TypeError('only valid absolute URLs can be requested'); + } const optsFn = this[HTTP_OPTIONS]; let opts = options; @@ -36,21 +63,117 @@ module.exports = async function request(options, { accessToken, mTLS = false, DP }, DPoP, accessToken); } + let userOptions; if (optsFn) { - opts = optsFn.call(this, defaultsDeep({}, opts, DEFAULT_HTTP_OPTIONS)); + userOptions = pick( + optsFn.call(this, url, defaultsDeep({}, opts, DEFAULT_HTTP_OPTIONS)), + ...allowed, + ); } + opts = defaultsDeep({}, userOptions, opts, DEFAULT_HTTP_OPTIONS); - if ( - mTLS - && ( - (!opts.key || !opts.cert) - && (!opts.https || !((opts.https.key && opts.https.certificate) || opts.https.pfx)) - ) - ) { + if (mTLS && (!opts.pfx && !(opts.key && opts.cert))) { throw new TypeError('mutual-TLS certificate and key not set'); } - return got(opts); + if (opts.searchParams) { + // eslint-disable-next-line no-restricted-syntax + for (const [key, value] of Object.entries(opts.searchParams)) { + url.searchParams.delete(key); + url.searchParams.set(key, value); + } + } + + let responseType; + let form; + let json; + let body; + ({ + // eslint-disable-next-line prefer-const + form, responseType, json, body, ...opts + } = opts); + + // eslint-disable-next-line no-restricted-syntax + for (const [key, value] of Object.entries(opts.headers || {})) { + if (value === undefined) { + delete opts.headers[key]; + } + } + + let response; + const req = (url.protocol === 'https:' ? https.request : http.request)(url, opts); + return (async () => { + // if (GET (and other && form, json, body)) throw; + if (json) { + req.removeHeader('content-type'); + req.setHeader('content-type', 'application/json'); + req.write(JSON.stringify(json)); + } else if (form) { + req.removeHeader('content-type'); + req.setHeader('content-type', 'application/x-www-form-urlencoded'); + req.write(querystring.stringify(form)); + } else if (body) { + req.write(body); + } + + req.end(); + + [response] = await Promise.race([once(req, 'response'), once(req, 'timeout')]); + + // timeout reached + if (!response) { + req.destroy(); + throw new RPError(`outgoing request timed out after ${opts.timeout}ms`); + } + + const parts = []; + // eslint-disable-next-line no-restricted-syntax + for await (const part of response) { + parts.push(part); + } + + if (parts.length) { + switch (responseType) { + case 'json': { + Object.defineProperty(response, 'body', { + get() { + let value = Buffer.concat(parts); + try { + value = JSON.parse(value); + } catch (err) { + Object.defineProperty(err, 'response', response); + throw err; + } finally { + Object.defineProperty(response, 'body', { value, configurable: true }); + } + return value; + }, + configurable: true, + }); + break; + } + case undefined: + case 'buffer': { + Object.defineProperty(response, 'body', { + get() { + const value = Buffer.concat(parts); + Object.defineProperty(response, 'body', { value, configurable: true }); + return value; + }, + configurable: true, + }); + break; + } + default: + throw new TypeError('unsupported responseType request option'); + } + } + + return response; + })().catch((err) => { + Object.defineProperty(err, 'response', response); + throw err; + }); }; -module.exports.setDefaults = setDefaults; +module.exports.setDefaults = setDefaults.bind(undefined, allowed); diff --git a/lib/issuer.js b/lib/issuer.js index 1b6170ca..9885b160 100644 --- a/lib/issuer.js +++ b/lib/issuer.js @@ -4,7 +4,7 @@ const { inspect } = require('util'); const url = require('url'); const jose = require('jose'); -const LRU = require('lru-cache'); +const QuickLRU = require('quick-lru'); const objectHash = require('object-hash'); const { RPError } = require('./errors'); @@ -57,7 +57,7 @@ class Issuer { } }); - instance(this).set('cache', new LRU({ max: 100 })); + instance(this).set('cache', new QuickLRU({ maxSize: 100 })); registry.set(this.issuer, this); @@ -80,7 +80,7 @@ class Issuer { const cache = instance(this).get('cache'); if (reload || !keystore) { - cache.reset(); + cache.clear(); const response = await request.call(this, { method: 'GET', responseType: 'json', @@ -168,7 +168,6 @@ class Issuer { url: webfingerUrl, responseType: 'json', searchParams: { resource, rel: REL }, - followRedirect: true, }); const body = processResponse(response); diff --git a/package.json b/package.json index d09ccec4..b16c2ab7 100644 --- a/package.json +++ b/package.json @@ -52,14 +52,15 @@ ] }, "dependencies": { - "got": "^11.8.0", + "cacheable-lookup": "^6.0.4", "jose": "^2.0.5", - "lru-cache": "^6.0.0", "make-error": "^1.3.6", "object-hash": "^2.0.1", - "oidc-token-hash": "^5.0.1" + "oidc-token-hash": "^5.0.1", + "quick-lru": "^5.1.1" }, "devDependencies": { + "@types/node": "^16.11.1", "@types/passport": "^1.0.4", "base64url": "^3.0.1", "chai": "^4.2.0", diff --git a/test/client/client_instance.test.js b/test/client/client_instance.test.js index d4b30600..d887f6f6 100644 --- a/test/client/client_instance.test.js +++ b/test/client/client_instance.test.js @@ -1352,8 +1352,7 @@ describe('Client', () => { return client.userinfo() .then(fail, function (error) { - expect(error.name).to.eql('ParseError'); - expect(error.message).to.eql('Unexpected token } in JSON at position 12 in "https://op.example.com/me"'); + expect(error.message).to.eql('Unexpected token } in JSON at position 12'); expect(error).to.have.property('response'); }); }); @@ -1542,8 +1541,7 @@ describe('Client', () => { return client.introspect('tokenValue') .then(fail, function (error) { - expect(error.name).to.eql('ParseError'); - expect(error.message).to.eql('Unexpected token } in JSON at position 12 in "https://op.example.com/token/introspect"'); + expect(error.message).to.eql('Unexpected token } in JSON at position 12'); expect(error).to.have.property('response'); }); }); diff --git a/test/client/discover_client.test.js b/test/client/discover_client.test.js index d63fa259..b4fd4f9d 100644 --- a/test/client/discover_client.test.js +++ b/test/client/discover_client.test.js @@ -73,8 +73,7 @@ describe('Client#fromUri()', () => { return issuer.Client.fromUri('https://op.example.com/client/identifier') .then(fail, function (error) { - expect(error.name).to.eql('ParseError'); - expect(error.message).to.eql('Unexpected token } in JSON at position 12 in "https://op.example.com/client/identifier"'); + expect(error.message).to.eql('Unexpected token } in JSON at position 12'); expect(error).to.have.property('response'); }); }); @@ -85,10 +84,7 @@ describe('Client#fromUri()', () => { }); it('allows for http options to be defined for issuer.Client.fromUri calls', async () => { - const httpOptions = sinon.stub().callsFake((opts) => { - opts.headers.custom = 'foo'; - return opts; - }); + const httpOptions = sinon.stub().callsFake(() => ({ headers: { custom: 'foo' } })); issuer.Client[custom.http_options] = httpOptions; nock('https://op.example.com') diff --git a/test/client/dpop.test.js b/test/client/dpop.test.js index e89507b0..6d561ff6 100644 --- a/test/client/dpop.test.js +++ b/test/client/dpop.test.js @@ -24,7 +24,7 @@ describe('DPoP', () => { client_id: 'client', token_endpoint_auth_method: 'none', }); - this.client[custom.http_options] = (opts) => { + this.client[custom.http_options] = (url, opts) => { this.httpOpts = opts; return opts; }; diff --git a/test/client/mtls.test.js b/test/client/mtls.test.js index ec26b077..fb5691f8 100644 --- a/test/client/mtls.test.js +++ b/test/client/mtls.test.js @@ -92,7 +92,7 @@ describe('mutual-TLS', () => { token_endpoint_auth_method: 'self_signed_tls_client_auth', tls_client_certificate_bound_access_tokens: true, }); - this.client[custom.http_options] = (opts) => ({ ...opts, https: { key, certificate: cert } }); + this.client[custom.http_options] = () => ({ key, cert }); this.jwtAuthClient = new issuer.Client({ client_id: 'client', client_secret: 'secret', @@ -100,7 +100,7 @@ describe('mutual-TLS', () => { token_endpoint_auth_signing_alg: 'HS256', tls_client_certificate_bound_access_tokens: true, }); - this.client[custom.http_options] = (opts) => ({ ...opts, https: { key, certificate: cert } }); + this.client[custom.http_options] = () => ({ key, cert }); }); it('uses the mtls endpoint alias for token endpoint when using jwt auth and tls certs', async function () { @@ -174,7 +174,7 @@ describe('mutual-TLS', () => { }); it('works with a PKCS#12 file and a passphrase', async function () { - this.client[custom.http_options] = (opts) => ({ ...opts, https: { pfx } }); + this.client[custom.http_options] = () => ({ pfx }); nock('https://mtls.op.example.com') .get('/me').reply(200, { sub: 'foo' }); diff --git a/test/client/register_client.test.js b/test/client/register_client.test.js index cbeed298..c27acfda 100644 --- a/test/client/register_client.test.js +++ b/test/client/register_client.test.js @@ -86,8 +86,7 @@ describe('Client#register', () => { return issuer.Client.register({}) .then(fail, function (error) { - expect(error.name).to.eql('ParseError'); - expect(error.message).to.eql('Unexpected token } in JSON at position 12 in "https://op.example.com/client/registration"'); + expect(error.message).to.eql('Unexpected token } in JSON at position 12'); expect(error).to.have.property('response'); }); }); @@ -207,10 +206,7 @@ describe('Client#register', () => { }); it('allows for http options to be defined for issuer.Client.register calls', async () => { - const httpOptions = sinon.stub().callsFake((opts) => { - opts.headers.custom = 'foo'; - return opts; - }); + const httpOptions = sinon.stub().callsFake(() => ({ headers: { custom: 'foo' } })); issuer.Client[custom.http_options] = httpOptions; nock('https://op.example.com') diff --git a/test/issuer/discover_issuer.test.js b/test/issuer/discover_issuer.test.js index cfbf57af..5589b575 100644 --- a/test/issuer/discover_issuer.test.js +++ b/test/issuer/discover_issuer.test.js @@ -235,8 +235,7 @@ describe('Issuer#discover()', () => { return Issuer.discover('https://op.example.com') .then(fail, function (error) { - expect(error.name).to.eql('ParseError'); - expect(error.message).to.eql('Unexpected token } in JSON at position 12 in "https://op.example.com/.well-known/openid-configuration"'); + expect(error.message).to.eql('Unexpected token } in JSON at position 12'); expect(error).to.have.property('response'); }); }); @@ -276,10 +275,7 @@ describe('Issuer#discover()', () => { .get('/.well-known/openid-configuration') .reply(200, success); - const httpOptions = sinon.stub().callsFake((opts) => { - opts.headers.custom = 'foo'; - return opts; - }); + const httpOptions = sinon.stub().callsFake(() => ({ headers: { custom: 'foo' } })); Issuer[custom.http_options] = httpOptions; await Issuer.discover('https://op.example.com/.well-known/openid-configuration'); diff --git a/test/issuer/discover_webfinger.test.js b/test/issuer/discover_webfinger.test.js index fdf73015..67656788 100644 --- a/test/issuer/discover_webfinger.test.js +++ b/test/issuer/discover_webfinger.test.js @@ -255,10 +255,7 @@ describe('Issuer#webfinger()', () => { }); it('allows for http options to be defined for Issuer.webfinger calls', async () => { - const httpOptions = sinon.stub().callsFake((opts) => { - opts.headers.custom = 'foo'; - return opts; - }); + const httpOptions = sinon.stub().callsFake(() => ({ headers: { custom: 'foo' } })); Issuer[custom.http_options] = httpOptions; nock('https://opemail.example.com') diff --git a/test/issuer/issuer_instance.test.js b/test/issuer/issuer_instance.test.js index ba6bc4a4..0054e856 100644 --- a/test/issuer/issuer_instance.test.js +++ b/test/issuer/issuer_instance.test.js @@ -1,5 +1,5 @@ const { expect } = require('chai'); -const LRU = require('lru-cache'); +const QuickLRU = require('quick-lru'); const nock = require('nock'); const sinon = require('sinon'); const jose = require('jose'); @@ -40,7 +40,7 @@ describe('Issuer', () => { after(nock.cleanAll); afterEach(function () { - if (LRU.prototype.get.restore) LRU.prototype.get.restore(); + if (QuickLRU.prototype.get.restore) QuickLRU.prototype.get.restore(); }); it('does not refetch immidiately', function () { @@ -64,7 +64,7 @@ describe('Issuer', () => { }); it('asks to fetch if the keystore is stale and new key definition is requested', function () { - sinon.stub(LRU.prototype, 'get').returns(undefined); + sinon.stub(QuickLRU.prototype, 'get').returns(undefined); return this.issuer.queryKeyStore({ kid: 'yeah' }).then(fail, () => { nock('https://op.example.com') .get('/certs') @@ -83,7 +83,7 @@ describe('Issuer', () => { }); it('requires a kid is provided in definition if more keys are in the storage', function () { - sinon.stub(LRU.prototype, 'get').returns(undefined); + sinon.stub(QuickLRU.prototype, 'get').returns(undefined); return this.keystore.generate('RSA').then(() => { nock('https://op.example.com') .get('/certs') @@ -97,7 +97,7 @@ describe('Issuer', () => { }); it('multiple keys can match the JWT header', function () { - sinon.stub(LRU.prototype, 'get').returns(undefined); + sinon.stub(QuickLRU.prototype, 'get').returns(undefined); const { kid } = this.keystore.get({ kty: 'RSA' }); return this.keystore.generate('RSA', undefined, { kid }).then(() => { nock('https://op.example.com') @@ -121,10 +121,7 @@ describe('Issuer', () => { .get('/certs') .reply(200, this.keystore.toJWKS()); - const httpOptions = sinon.stub().callsFake((opts) => { - opts.headers.custom = 'foo'; - return opts; - }); + const httpOptions = sinon.stub().callsFake(() => ({ headers: { custom: 'foo' } })); this.issuer[custom.http_options] = httpOptions; await this.issuer.keystore(true); diff --git a/types/index.d.ts b/types/index.d.ts index d5b9e3a1..b4568f38 100644 --- a/types/index.d.ts +++ b/types/index.d.ts @@ -6,16 +6,16 @@ * @see https://github.com/panva/node-openid-client/blob/master/docs/README.md */ import * as http from "http"; +import * as https from "https"; import * as http2 from "http2"; -import { Options as GotOptions, CancelableRequest, Response } from "got"; import { URL } from "url"; import * as jose from "jose"; import * as crypto from "crypto"; -export type HttpOptions = GotOptions; +export type HttpOptions = Pick export type RetryFunction = (retry: number, error: Error) => number; -export type CustomHttpOptionsProvider = (options: HttpOptions) => HttpOptions; +export type CustomHttpOptionsProvider = (options: HttpOptions & { url: URL } & UnknownObject) => HttpOptions; export type TokenTypeHint = "access_token" | "refresh_token" | string; export type DPoPInput = | crypto.KeyObject diff --git a/types/openid-client-tests.ts b/types/openid-client-tests.ts index 27b8babc..941219c7 100644 --- a/types/openid-client-tests.ts +++ b/types/openid-client-tests.ts @@ -8,15 +8,7 @@ import passport from 'passport'; async (req: IncomingMessage) => { // Custom HTTP options on the `Issuer` _c'tor_ (e.g. used for `Issuer.discover()`): - Issuer[custom.http_options] = options => { - console.log(options.followRedirect, options.timeout, options.retry); - return { - ...options, - followRedirect: true, - timeout: 10_000, - retry: 3, - }; - }; + Issuer[custom.http_options] = () => ({ timeout: 10000 }); let issuer = await Issuer.discover('https://accounts.google.com'); console.log('Discovered issuer %O', issuer.metadata.issuer); @@ -35,11 +27,11 @@ async (req: IncomingMessage) => { token_endpoint_auth_methods_supported: ['client_secret_post', 'client_secret_basic'], }); - issuer[custom.http_options] = options => ({ ...options, retry: 3 }); + issuer[custom.http_options] = () => ({ timeout: 10000 }); // - issuer.Client[custom.http_options] = options => ({ ...options, retry: 3 }); + issuer.Client[custom.http_options] = () => ({ timeout: 10000 }); const client = new issuer.Client({ client_id: 'c', @@ -50,7 +42,7 @@ async (req: IncomingMessage) => { console.log(client.metadata.client_id); // Custom HTTP options on the `Client` _instance_ - client[custom.http_options] = options => ({ ...options, retry: 3 }); + client[custom.http_options] = () => ({ timeout: 10000 }); client[custom.clock_tolerance] = 5; //