Add node modules and compiled JavaScript from main (#54)

Co-authored-by: Oliver King <oking3@uncc.edu>
This commit is contained in:
github-actions[bot]
2022-06-29 15:41:55 -04:00
committed by GitHub
parent 4a983766a0
commit 52d71d28bd
6814 changed files with 2048539 additions and 2 deletions

21
node_modules/openid-client/LICENSE.md generated vendored Normal file
View File

@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright (c) 2016 Filip Skokan
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

317
node_modules/openid-client/README.md generated vendored Normal file
View File

@ -0,0 +1,317 @@
# openid-client
openid-client is a server side [OpenID][openid-connect] Relying Party (RP, Client) implementation for
Node.js runtime, supports [passport][passport-url].
## Implemented specs & features
The following client/RP features from OpenID Connect/OAuth2.0 specifications are implemented by
openid-client.
- [OpenID Connect Core 1.0][feature-core]
- Authorization Callback
- Authorization Code Flow
- Implicit Flow
- Hybrid Flow
- UserInfo Request
- Fetching Distributed Claims
- Unpacking Aggregated Claims
- Offline Access / Refresh Token Grant
- Client Credentials Grant
- Client Authentication
- none
- client_secret_basic
- client_secret_post
- client_secret_jwt
- private_key_jwt
- Consuming Self-Issued OpenID Provider ID Token response
- [RFC8414 - OAuth 2.0 Authorization Server Metadata][feature-oauth-discovery] and [OpenID Connect Discovery 1.0][feature-discovery]
- Discovery of OpenID Provider (Issuer) Metadata
- Discovery of OpenID Provider (Issuer) Metadata via user provided inputs (via [webfinger][documentation-webfinger])
- [OpenID Connect Dynamic Client Registration 1.0][feature-registration]
- Dynamic Client Registration request
- Client initialization via registration client uri
- [RFC7009 - OAuth 2.0 Token revocation][feature-revocation]
- Client Authenticated request to token revocation
- [RFC7662 - OAuth 2.0 Token introspection][feature-introspection]
- Client Authenticated request to token introspection
- [RFC8628 - OAuth 2.0 Device Authorization Grant (Device Flow)][feature-device-flow]
- [RFC8705 - OAuth 2.0 Mutual TLS Client Authentication and Certificate-Bound Access Tokens][feature-mtls]
- Mutual TLS Client Certificate-Bound Access Tokens
- Metadata for Mutual TLS Endpoint Aliases
- Client Authentication
- tls_client_auth
- self_signed_tls_client_auth
- [RFC9101 - OAuth 2.0 JWT-Secured Authorization Request (JAR)][feature-jar]
- [RFC9126 - OAuth 2.0 Pushed Authorization Requests (PAR)][feature-par]
- [OpenID Connect Session Management 1.0 - draft 28][feature-rp-logout]
- 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]
- [OAuth 2.0 Demonstration of Proof-of-Possession at the Application Layer (DPoP) - draft 03][feature-dpop]
Updates to draft specifications (DPoP, 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
[<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]
Filip Skokan has [certified][openid-certified-link] that [openid-client][npm-url]
conforms to the following profiles of the OpenID Connect™ protocol
- RP Basic, Implicit, Hybrid, Config, Dynamic, and Form Post
- RP FAPI R/W MTLS and Private Key
## Sponsor
[<img width="65" height="65" align="left" src="https://avatars.githubusercontent.com/u/2824157?s=75&v=4" alt="auth0-logo">][sponsor-auth0] If you want to quickly add OpenID Connect authentication to Node.js apps, feel free to check out Auth0's Node.js SDK and free plan at [auth0.com/developers][sponsor-auth0].<br><br>
## Support
If you or your business use openid-client, please consider becoming a [sponsor][support-sponsor] so I can continue maintaining it and adding new features carefree.
## Documentation
The library exposes what are essentially steps necessary to be done by a relying party consuming
OpenID Connect Authorization Server responses or wrappers around requests to its endpoints. Aside
from a generic OpenID Connect [passport][passport-url] strategy it does not expose neither express
or koa middlewares. Those can however be built using the exposed API.
- [openid-client API Documentation][documentation]
- [Issuer][documentation-issuer]
- [Client][documentation-client]
- [Customizing][documentation-customizing]
- [TokenSet][documentation-tokenset]
- [Strategy][documentation-strategy]
- [generators][documentation-generators]
- [errors][documentation-errors]
## Install
Node.js version **>=12.0.0** is recommended, but **^10.19.0** lts/dubnium is also supported.
```console
npm install openid-client
```
## Quick start
Discover an Issuer configuration using its published .well-known endpoints
```js
const { Issuer } = require('openid-client');
Issuer.discover('https://accounts.google.com') // => Promise
.then(function (googleIssuer) {
console.log('Discovered issuer %s %O', googleIssuer.issuer, googleIssuer.metadata);
});
```
### Authorization Code Flow
Authorization Code flow is for obtaining Access Tokens (and optionally Refresh Tokens) to use with
third party APIs securely as well as Refresh Tokens. In this quick start your application also uses
PKCE instead of `state` parameter for CSRF protection.
Create a Client instance for that issuer's authorization server intended for Authorization Code
flow.
**See the [documentation][documentation] for full API details.**
```js
const client = new googleIssuer.Client({
client_id: 'zELcpfANLqY7Oqas',
client_secret: 'TQV5U29k1gHibH5bx1layBo0OSAvAbRT3UYW3EWrSYBB5swxjVfWUa1BS8lqzxG/0v9wruMcrGadany3',
redirect_uris: ['http://localhost:3000/cb'],
response_types: ['code'],
// id_token_signed_response_alg (default "RS256")
// token_endpoint_auth_method (default "client_secret_basic")
}); // => Client
```
When you want to have your end-users authorize you need to send them to the issuer's
`authorization_endpoint`. Consult the web framework of your choice on how to redirect but here's how
to get the authorization endpoint's URL with parameters already encoded in the query to redirect
to.
```js
const { generators } = require('openid-client');
const code_verifier = generators.codeVerifier();
// store the code_verifier in your framework's session mechanism, if it is a cookie based solution
// it should be httpOnly (not readable by javascript) and encrypted.
const code_challenge = generators.codeChallenge(code_verifier);
client.authorizationUrl({
scope: 'openid email profile',
resource: 'https://my.api.example.com/resource/32178',
code_challenge,
code_challenge_method: 'S256',
});
```
When end-users are redirected back to your `redirect_uri` your application consumes the callback and
passes in the `code_verifier` to include it in the authorization code grant token exchange.
```js
const params = client.callbackParams(req);
client.callback('https://client.example.com/callback', params, { code_verifier }) // => Promise
.then(function (tokenSet) {
console.log('received and validated tokens %j', tokenSet);
console.log('validated ID Token claims %j', tokenSet.claims());
});
```
You can then call the `userinfo_endpoint`.
```js
client.userinfo(access_token) // => Promise
.then(function (userinfo) {
console.log('userinfo %j', userinfo);
});
```
And later refresh the tokenSet if it had a `refresh_token`.
```js
client.refresh(refresh_token) // => Promise
.then(function (tokenSet) {
console.log('refreshed and validated tokens %j', tokenSet);
console.log('refreshed ID Token claims %j', tokenSet.claims());
});
```
### Implicit ID Token Flow
Implicit `response_type=id_token` flow is perfect for simply authenticating your end-users, assuming
the only job you want done is authenticating the user and then relying on your own session mechanism
with no need for accessing any third party APIs with an Access Token from the Authorization Server.
Create a Client instance for that issuer's authorization server intended for ID Token implicit flow.
**See the [documentation][documentation] for full API details.**
```js
const client = new googleIssuer.Client({
client_id: 'zELcpfANLqY7Oqas',
redirect_uris: ['http://localhost:3000/cb'],
response_types: ['id_token'],
// id_token_signed_response_alg (default "RS256")
}); // => Client
```
When you want to have your end-users authorize you need to send them to the issuer's
`authorization_endpoint`. Consult the web framework of your choice on how to redirect but here's how
to get the authorization endpoint's URL with parameters already encoded in the query to redirect
to.
```js
const { generators } = require('openid-client');
const nonce = generators.nonce();
// store the nonce in your framework's session mechanism, if it is a cookie based solution
// it should be httpOnly (not readable by javascript) and encrypted.
client.authorizationUrl({
scope: 'openid email profile',
response_mode: 'form_post',
nonce,
});
```
When end-users hit back your `redirect_uri` with a POST (authorization request included `form_post`
response mode) your application consumes the callback and passes the `nonce` in to include it in the
ID Token verification steps.
```js
// assumes req.body is populated from your web framework's body parser
const params = client.callbackParams(req);
client.callback('https://client.example.com/callback', params, { nonce }) // => Promise
.then(function (tokenSet) {
console.log('received and validated tokens %j', tokenSet);
console.log('validated ID Token claims %j', tokenSet.claims());
});
```
### Device Authorization Grant (Device Flow)
[RFC8628 - OAuth 2.0 Device Authorization Grant (Device Flow)](https://tools.ietf.org/html/rfc8628)
is started by starting a Device Authorization Request.
```js
const handle = await client.deviceAuthorization();
console.log('User Code: ', handle.user_code);
console.log('Verification URI: ', handle.verification_uri);
console.log('Verification URI (complete): ', handle.verification_uri_complete);
```
The handle represents a Device Authorization Response with the `verification_uri`, `user_code` and
other defined response properties.
You will display the instructions to the end-user and have him directed at `verification_uri` or
`verification_uri_complete`, afterwards you can start polling for the Device Access Token Response.
```js
const tokenSet = await handle.poll();
console.log('received tokens %j', tokenSet);
```
This will poll in the defined interval and only resolve with a TokenSet once one is received. This
will handle the defined `authorization_pending` and `slow_down` "soft" errors and continue polling
but upon any other error it will reject. With tokenSet received you can throw away the handle.
## Electron Support
Electron >=v6.0.0 runtime is supported to the extent of the crypto engine BoringSSL feature parity
with standard Node.js OpenSSL.
## FAQ
#### Semver?
**Yes.** Everything that's either exported in the TypeScript definitions file or
[documented][documentation] is subject to
[Semantic Versioning 2.0.0](https://semver.org/spec/v2.0.0.html). The rest is to be considered
private API and is subject to change between any versions.
#### How do I use it outside of Node.js
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.
#### How to make the client send client_id and client_secret in the body?
See [Client Authentication Methods (docs)][documentation-methods].
#### Can I adjust the HTTP timeout?
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
[feature-discovery]: https://openid.net/specs/openid-connect-discovery-1_0.html
[feature-oauth-discovery]: https://tools.ietf.org/html/rfc8414
[feature-registration]: https://openid.net/specs/openid-connect-registration-1_0.html
[feature-revocation]: https://tools.ietf.org/html/rfc7009
[feature-introspection]: https://tools.ietf.org/html/rfc7662
[feature-mtls]: https://tools.ietf.org/html/rfc8705
[feature-device-flow]: https://tools.ietf.org/html/rfc8628
[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
[feature-dpop]: https://tools.ietf.org/html/draft-ietf-oauth-dpop-03
[feature-par]: https://www.rfc-editor.org/rfc/rfc9126.html
[feature-jar]: https://www.rfc-editor.org/rfc/rfc9101.html
[openid-certified-link]: https://openid.net/certification/
[passport-url]: http://passportjs.org
[npm-url]: https://www.npmjs.com/package/openid-client
[sponsor-auth0]: https://auth0.com/developers?utm_source=GHsponsor&utm_medium=GHsponsor&utm_campaign=openid-client&utm_content=auth
[support-sponsor]: https://github.com/sponsors/panva
[documentation]: https://github.com/panva/node-openid-client/blob/master/docs/README.md
[documentation-issuer]: https://github.com/panva/node-openid-client/blob/master/docs/README.md#issuer
[documentation-client]: https://github.com/panva/node-openid-client/blob/master/docs/README.md#client
[documentation-customizing]: https://github.com/panva/node-openid-client/blob/master/docs/README.md#customizing
[documentation-tokenset]: https://github.com/panva/node-openid-client/blob/master/docs/README.md#tokenset
[documentation-strategy]: https://github.com/panva/node-openid-client/blob/master/docs/README.md#strategy
[documentation-errors]: https://github.com/panva/node-openid-client/blob/master/docs/README.md#errors
[documentation-generators]: https://github.com/panva/node-openid-client/blob/master/docs/README.md#generators
[documentation-methods]: https://github.com/panva/node-openid-client/blob/master/docs/README.md#client-authentication-methods
[documentation-webfinger]: https://github.com/panva/node-openid-client/blob/master/docs/README.md#issuerwebfingerinput

1733
node_modules/openid-client/lib/client.js generated vendored Normal file

File diff suppressed because it is too large Load Diff

123
node_modules/openid-client/lib/device_flow_handle.js generated vendored Normal file
View File

@ -0,0 +1,123 @@
/* eslint-disable camelcase */
const { inspect } = require('util');
const { RPError, OPError } = require('./errors');
const instance = require('./helpers/weak_cache');
const now = require('./helpers/unix_timestamp');
const { authenticatedPost } = require('./helpers/client');
const processResponse = require('./helpers/process_response');
const TokenSet = require('./token_set');
class DeviceFlowHandle {
constructor({
client, exchangeBody, clientAssertionPayload, response, maxAge, DPoP,
}) {
['verification_uri', 'user_code', 'device_code'].forEach((prop) => {
if (typeof response[prop] !== 'string' || !response[prop]) {
throw new RPError(`expected ${prop} string to be returned by Device Authorization Response, got %j`, response[prop]);
}
});
if (!Number.isSafeInteger(response.expires_in)) {
throw new RPError('expected expires_in number to be returned by Device Authorization Response, got %j', response.expires_in);
}
instance(this).expires_at = now() + response.expires_in;
instance(this).client = client;
instance(this).DPoP = DPoP;
instance(this).maxAge = maxAge;
instance(this).exchangeBody = exchangeBody;
instance(this).clientAssertionPayload = clientAssertionPayload;
instance(this).response = response;
instance(this).interval = response.interval * 1000 || 5000;
}
abort() {
instance(this).aborted = true;
}
async poll({ signal } = {}) {
if ((signal && signal.aborted) || instance(this).aborted) {
throw new RPError('polling aborted');
}
if (this.expired()) {
throw new RPError('the device code %j has expired and the device authorization session has concluded', this.device_code);
}
await new Promise((resolve) => setTimeout(resolve, instance(this).interval));
const response = await authenticatedPost.call(
instance(this).client,
'token',
{
form: {
...instance(this).exchangeBody,
grant_type: 'urn:ietf:params:oauth:grant-type:device_code',
device_code: this.device_code,
},
responseType: 'json',
},
{ clientAssertionPayload: instance(this).clientAssertionPayload, DPoP: instance(this).DPoP },
);
let responseBody;
try {
responseBody = processResponse(response);
} catch (err) {
switch (err instanceof OPError && err.error) {
case 'slow_down':
instance(this).interval += 5000;
case 'authorization_pending': // eslint-disable-line no-fallthrough
return this.poll({ signal });
default:
throw err;
}
}
const tokenset = new TokenSet(responseBody);
if ('id_token' in tokenset) {
await instance(this).client.decryptIdToken(tokenset);
await instance(this).client.validateIdToken(tokenset, undefined, 'token', instance(this).maxAge);
}
return tokenset;
}
get device_code() {
return instance(this).response.device_code;
}
get user_code() {
return instance(this).response.user_code;
}
get verification_uri() {
return instance(this).response.verification_uri;
}
get verification_uri_complete() {
return instance(this).response.verification_uri_complete;
}
get expires_in() {
return Math.max.apply(null, [instance(this).expires_at - now(), 0]);
}
expired() {
return this.expires_in === 0;
}
/* istanbul ignore next */
[inspect.custom]() {
return `${this.constructor.name} ${inspect(instance(this).response, {
depth: Infinity,
colors: process.stdout.isTTY,
compact: false,
sorted: true,
})}`;
}
}
module.exports = DeviceFlowHandle;

61
node_modules/openid-client/lib/errors.js generated vendored Normal file
View File

@ -0,0 +1,61 @@
/* eslint-disable camelcase */
const { format } = require('util');
const makeError = require('make-error');
function OPError({
error_description,
error,
error_uri,
session_state,
state,
scope,
}, response) {
OPError.super.call(this, !error_description ? error : `${error} (${error_description})`);
Object.assign(
this,
{ error },
(error_description && { error_description }),
(error_uri && { error_uri }),
(state && { state }),
(scope && { scope }),
(session_state && { session_state }),
);
if (response) {
Object.defineProperty(this, 'response', {
value: response,
});
}
}
makeError(OPError);
function RPError(...args) {
if (typeof args[0] === 'string') {
RPError.super.call(this, format(...args));
} else {
const {
message, printf, response, ...rest
} = args[0];
if (printf) {
RPError.super.call(this, format(...printf));
} else {
RPError.super.call(this, message);
}
Object.assign(this, rest);
if (response) {
Object.defineProperty(this, 'response', {
value: response,
});
}
}
}
makeError(RPError);
module.exports = {
OPError,
RPError,
};

22
node_modules/openid-client/lib/helpers/assert.js generated vendored Normal file
View File

@ -0,0 +1,22 @@
function assertSigningAlgValuesSupport(endpoint, issuer, properties) {
if (!issuer[`${endpoint}_endpoint`]) return;
const eam = `${endpoint}_endpoint_auth_method`;
const easa = `${endpoint}_endpoint_auth_signing_alg`;
const easavs = `${endpoint}_endpoint_auth_signing_alg_values_supported`;
if (properties[eam] && properties[eam].endsWith('_jwt') && !properties[easa] && !issuer[easavs]) {
throw new TypeError(`${easavs} must be configured on the issuer if ${easa} is not defined on a client`);
}
}
function assertIssuerConfiguration(issuer, endpoint) {
if (!issuer[endpoint]) {
throw new TypeError(`${endpoint} must be configured on the issuer`);
}
}
module.exports = {
assertSigningAlgValuesSupport,
assertIssuerConfiguration,
};

12
node_modules/openid-client/lib/helpers/base64url.js generated vendored Normal file
View File

@ -0,0 +1,12 @@
let encode;
if (Buffer.isEncoding('base64url')) {
encode = (input, encoding = 'utf8') => Buffer.from(input, encoding).toString('base64url');
} else {
const fromBase64 = (base64) => base64.replace(/=/g, '').replace(/\+/g, '-').replace(/\//g, '_');
encode = (input, encoding = 'utf8') => fromBase64(Buffer.from(input, encoding).toString('base64'));
}
const decode = (input) => Buffer.from(input, 'base64');
module.exports.decode = decode;
module.exports.encode = encode;

170
node_modules/openid-client/lib/helpers/client.js generated vendored Normal file
View File

@ -0,0 +1,170 @@
const jose = require('jose');
const { assertIssuerConfiguration } = require('./assert');
const { random } = require('./generators');
const now = require('./unix_timestamp');
const request = require('./request');
const instance = require('./weak_cache');
const merge = require('./merge');
const formUrlEncode = (value) => encodeURIComponent(value).replace(/%20/g, '+');
async function clientAssertion(endpoint, payload) {
let alg = this[`${endpoint}_endpoint_auth_signing_alg`];
if (!alg) {
assertIssuerConfiguration(this.issuer, `${endpoint}_endpoint_auth_signing_alg_values_supported`);
}
if (this[`${endpoint}_endpoint_auth_method`] === 'client_secret_jwt') {
const key = await this.joseSecret();
if (!alg) {
const supported = this.issuer[`${endpoint}_endpoint_auth_signing_alg_values_supported`];
alg = Array.isArray(supported) && supported.find((signAlg) => key.algorithms('sign').has(signAlg));
}
return jose.JWS.sign(payload, key, { alg, typ: 'JWT' });
}
const keystore = instance(this).get('keystore');
if (!keystore) {
throw new TypeError('no client jwks provided for signing a client assertion with');
}
if (!alg) {
const algs = new Set();
keystore.all().forEach((key) => {
key.algorithms('sign').forEach(Set.prototype.add.bind(algs));
});
const supported = this.issuer[`${endpoint}_endpoint_auth_signing_alg_values_supported`];
alg = Array.isArray(supported) && supported.find((signAlg) => algs.has(signAlg));
}
const key = keystore.get({ alg, use: 'sig' });
if (!key) {
throw new TypeError(`no key found in client jwks to sign a client assertion with using alg ${alg}`);
}
return jose.JWS.sign(payload, key, { alg, typ: 'JWT', kid: key.kid.startsWith('DONOTUSE.') ? undefined : key.kid });
}
async function authFor(endpoint, { clientAssertionPayload } = {}) {
const authMethod = this[`${endpoint}_endpoint_auth_method`];
switch (authMethod) {
case 'self_signed_tls_client_auth':
case 'tls_client_auth':
case 'none':
return { form: { client_id: this.client_id } };
case 'client_secret_post':
if (!this.client_secret) {
throw new TypeError('client_secret_post client authentication method requires a client_secret');
}
return { form: { client_id: this.client_id, client_secret: this.client_secret } };
case 'private_key_jwt':
case 'client_secret_jwt': {
const timestamp = now();
const mTLS = endpoint === 'token' && this.tls_client_certificate_bound_access_tokens;
const audience = [...new Set([
this.issuer.issuer,
this.issuer.token_endpoint,
this.issuer[`${endpoint}_endpoint`],
mTLS && this.issuer.mtls_endpoint_aliases
? this.issuer.mtls_endpoint_aliases.token_endpoint : undefined,
].filter(Boolean))];
const assertion = await clientAssertion.call(this, endpoint, {
iat: timestamp,
exp: timestamp + 60,
jti: random(),
iss: this.client_id,
sub: this.client_id,
aud: audience,
...clientAssertionPayload,
});
return {
form: {
client_id: this.client_id,
client_assertion: assertion,
client_assertion_type: 'urn:ietf:params:oauth:client-assertion-type:jwt-bearer',
},
};
}
default: { // client_secret_basic
// This is correct behaviour, see https://tools.ietf.org/html/rfc6749#section-2.3.1 and the
// related appendix. (also https://github.com/panva/node-openid-client/pull/91)
// > The client identifier is encoded using the
// > "application/x-www-form-urlencoded" encoding algorithm per
// > Appendix B, and the encoded value is used as the username; the client
// > password is encoded using the same algorithm and used as the
// > password.
if (!this.client_secret) {
throw new TypeError('client_secret_basic client authentication method requires a client_secret');
}
const encoded = `${formUrlEncode(this.client_id)}:${formUrlEncode(this.client_secret)}`;
const value = Buffer.from(encoded).toString('base64');
return { headers: { Authorization: `Basic ${value}` } };
}
}
}
function resolveResponseType() {
const { length, 0: value } = this.response_types;
if (length === 1) {
return value;
}
return undefined;
}
function resolveRedirectUri() {
const { length, 0: value } = this.redirect_uris || [];
if (length === 1) {
return value;
}
return undefined;
}
async function authenticatedPost(endpoint, opts, {
clientAssertionPayload, endpointAuthMethod = endpoint, DPoP,
} = {}) {
const auth = await authFor.call(this, endpointAuthMethod, { clientAssertionPayload });
const requestOpts = merge(opts, auth);
const mTLS = this[`${endpointAuthMethod}_endpoint_auth_method`].includes('tls_client_auth')
|| (endpoint === 'token' && this.tls_client_certificate_bound_access_tokens);
let targetUrl;
if (mTLS && this.issuer.mtls_endpoint_aliases) {
targetUrl = this.issuer.mtls_endpoint_aliases[`${endpoint}_endpoint`];
}
targetUrl = targetUrl || this.issuer[`${endpoint}_endpoint`];
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.form[key];
}
}
}
return request.call(this, {
...requestOpts,
method: 'POST',
url: targetUrl,
}, { mTLS, DPoP });
}
module.exports = {
resolveResponseType,
resolveRedirectUri,
authFor,
authenticatedPost,
};

62
node_modules/openid-client/lib/helpers/consts.js generated vendored Normal file
View File

@ -0,0 +1,62 @@
const OIDC_DISCOVERY = '/.well-known/openid-configuration';
const OAUTH2_DISCOVERY = '/.well-known/oauth-authorization-server';
const WEBFINGER = '/.well-known/webfinger';
const REL = 'http://openid.net/specs/connect/1.0/issuer';
const AAD_MULTITENANT_DISCOVERY = [
`https://login.microsoftonline.com/common${OIDC_DISCOVERY}`,
`https://login.microsoftonline.com/common/v2.0${OIDC_DISCOVERY}`,
`https://login.microsoftonline.com/organizations/v2.0${OIDC_DISCOVERY}`,
`https://login.microsoftonline.com/consumers/v2.0${OIDC_DISCOVERY}`,
];
const CLIENT_DEFAULTS = {
grant_types: ['authorization_code'],
id_token_signed_response_alg: 'RS256',
authorization_signed_response_alg: 'RS256',
response_types: ['code'],
token_endpoint_auth_method: 'client_secret_basic',
};
const ISSUER_DEFAULTS = {
claim_types_supported: ['normal'],
claims_parameter_supported: false,
grant_types_supported: ['authorization_code', 'implicit'],
request_parameter_supported: false,
request_uri_parameter_supported: true,
require_request_uri_registration: false,
response_modes_supported: ['query', 'fragment'],
token_endpoint_auth_methods_supported: ['client_secret_basic'],
};
const CALLBACK_PROPERTIES = [
'access_token', // 6749
'code', // 6749
'error', // 6749
'error_description', // 6749
'error_uri', // 6749
'expires_in', // 6749
'id_token', // Core 1.0
'state', // 6749
'token_type', // 6749
'session_state', // Session Management
'response', // JARM
];
const JWT_CONTENT = /^application\/jwt/;
const HTTP_OPTIONS = Symbol('openid-client.custom.http-options');
const CLOCK_TOLERANCE = Symbol('openid-client.custom.clock-tolerance');
module.exports = {
AAD_MULTITENANT_DISCOVERY,
CALLBACK_PROPERTIES,
CLIENT_DEFAULTS,
CLOCK_TOLERANCE,
HTTP_OPTIONS,
ISSUER_DEFAULTS,
JWT_CONTENT,
OAUTH2_DISCOVERY,
OIDC_DISCOVERY,
REL,
WEBFINGER,
};

1
node_modules/openid-client/lib/helpers/deep_clone.js generated vendored Normal file
View File

@ -0,0 +1 @@
module.exports = (obj) => JSON.parse(JSON.stringify(obj));

29
node_modules/openid-client/lib/helpers/defaults.js generated vendored Normal file
View File

@ -0,0 +1,29 @@
/* eslint-disable no-restricted-syntax, no-continue */
const isPlainObject = require('./is_plain_object');
function defaults(deep, target, ...sources) {
for (const source of sources) {
if (!isPlainObject(source)) {
continue;
}
for (const [key, value] of Object.entries(source)) {
/* istanbul ignore if */
if (key === '__proto__' || key === 'constructor') {
continue;
}
if (typeof target[key] === 'undefined' && typeof value !== 'undefined') {
target[key] = value;
}
if (deep && isPlainObject(target[key]) && isPlainObject(value)) {
defaults(true, target[key], value);
}
}
}
return target;
}
module.exports = defaults.bind(undefined, false);
module.exports.deep = defaults.bind(undefined, true);

13
node_modules/openid-client/lib/helpers/generators.js generated vendored Normal file
View File

@ -0,0 +1,13 @@
const { createHash, randomBytes } = require('crypto');
const base64url = require('./base64url');
const random = (bytes = 32) => base64url.encode(randomBytes(bytes));
module.exports = {
random,
state: random,
nonce: random,
codeVerifier: random,
codeChallenge: (codeVerifier) => base64url.encode(createHash('sha256').update(codeVerifier).digest()),
};

View File

@ -0,0 +1,12 @@
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');
}
};

View File

@ -0,0 +1 @@
module.exports = (a) => !!a && a.constructor === Object;

26
node_modules/openid-client/lib/helpers/merge.js generated vendored Normal file
View File

@ -0,0 +1,26 @@
/* eslint-disable no-restricted-syntax, no-param-reassign, no-continue */
const isPlainObject = require('./is_plain_object');
function merge(target, ...sources) {
for (const source of sources) {
if (!isPlainObject(source)) {
continue;
}
for (const [key, value] of Object.entries(source)) {
/* istanbul ignore if */
if (key === '__proto__' || key === 'constructor') {
continue;
}
if (isPlainObject(target[key]) && isPlainObject(value)) {
target[key] = merge(target[key], value);
} else if (typeof value !== 'undefined') {
target[key] = value;
}
}
}
return target;
}
module.exports = merge;

9
node_modules/openid-client/lib/helpers/pick.js generated vendored Normal file
View File

@ -0,0 +1,9 @@
module.exports = function pick(object, ...paths) {
const obj = {};
for (const path of paths) { // eslint-disable-line no-restricted-syntax
if (object[path]) {
obj[path] = object[path];
}
}
return obj;
};

View File

@ -0,0 +1,62 @@
const { STATUS_CODES } = require('http');
const { format } = require('util');
const { OPError } = require('../errors');
const REGEXP = /(\w+)=("[^"]*")/g;
const throwAuthenticateErrors = (response) => {
const params = {};
try {
while ((REGEXP.exec(response.headers['www-authenticate'])) !== null) {
if (RegExp.$1 && RegExp.$2) {
params[RegExp.$1] = RegExp.$2.slice(1, -1);
}
}
} catch (err) {}
if (params.error) {
throw new OPError(params, response);
}
};
const isStandardBodyError = (response) => {
let result = false;
try {
let jsonbody;
if (typeof response.body !== 'object' || Buffer.isBuffer(response.body)) {
jsonbody = JSON.parse(response.body);
} else {
jsonbody = response.body;
}
result = typeof jsonbody.error === 'string' && jsonbody.error.length;
if (result) response.body = jsonbody;
} catch (err) {}
return result;
};
function processResponse(response, { statusCode = 200, body = true, bearer = false } = {}) {
if (response.statusCode !== statusCode) {
if (bearer) {
throwAuthenticateErrors(response);
}
if (isStandardBodyError(response)) {
throw new OPError(response.body, response);
}
throw new OPError({
error: format('expected %i %s, got: %i %s', statusCode, STATUS_CODES[statusCode], response.statusCode, STATUS_CODES[response.statusCode]),
}, response);
}
if (body && !response.body) {
throw new OPError({
error: format('expected %i %s with body but no body was returned', statusCode, STATUS_CODES[statusCode]),
}, response);
}
return response.body;
}
module.exports = processResponse;

56
node_modules/openid-client/lib/helpers/request.js generated vendored Normal file
View File

@ -0,0 +1,56 @@
const Got = require('got');
const pkg = require('../../package.json');
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);
};
setDefaults({
followRedirect: false,
headers: { 'User-Agent': `${pkg.name}/${pkg.version} (${pkg.homepage})` },
retry: 0,
timeout: 3500,
throwHttpErrors: false,
});
module.exports = async function request(options, { accessToken, mTLS = false, DPoP } = {}) {
const { url } = options;
isAbsoluteUrl(url);
const optsFn = this[HTTP_OPTIONS];
let opts = options;
if (DPoP && 'dpopProof' in this) {
opts.headers = opts.headers || {};
opts.headers.DPoP = this.dpopProof({
htu: url,
htm: options.method,
}, DPoP, accessToken);
}
if (optsFn) {
opts = optsFn.call(this, defaultsDeep({}, opts, DEFAULT_HTTP_OPTIONS));
}
if (
mTLS
&& (
(!opts.key || !opts.cert)
&& (!opts.https || !((opts.https.key && opts.https.certificate) || opts.https.pfx))
)
) {
throw new TypeError('mutual-TLS certificate and key not set');
}
return got(opts);
};
module.exports.setDefaults = setDefaults;

View File

@ -0,0 +1 @@
module.exports = () => Math.floor(Date.now() / 1000);

8
node_modules/openid-client/lib/helpers/weak_cache.js generated vendored Normal file
View File

@ -0,0 +1,8 @@
const privateProps = new WeakMap();
module.exports = (ctx) => {
if (!privateProps.has(ctx)) {
privateProps.set(ctx, new Map([['metadata', new Map()]]));
}
return privateProps.get(ctx);
};

View File

@ -0,0 +1,71 @@
// Credit: https://github.com/rohe/pyoidc/blob/master/src/oic/utils/webfinger.py
// -- Normalization --
// A string of any other type is interpreted as a URI either the form of scheme
// "://" authority path-abempty [ "?" query ] [ "#" fragment ] or authority
// path-abempty [ "?" query ] [ "#" fragment ] per RFC 3986 [RFC3986] and is
// normalized according to the following rules:
//
// If the user input Identifier does not have an RFC 3986 [RFC3986] scheme
// portion, the string is interpreted as [userinfo "@"] host [":" port]
// path-abempty [ "?" query ] [ "#" fragment ] per RFC 3986 [RFC3986].
// If the userinfo component is present and all of the path component, query
// component, and port component are empty, the acct scheme is assumed. In this
// case, the normalized URI is formed by prefixing acct: to the string as the
// scheme. Per the 'acct' URI Scheme [ID.ietfappsawgaccturi], if there is an
// at-sign character ('@') in the userinfo component, it needs to be
// percent-encoded as described in RFC 3986 [RFC3986].
// For all other inputs without a scheme portion, the https scheme is assumed,
// and the normalized URI is formed by prefixing https:// to the string as the
// scheme.
// If the resulting URI contains a fragment portion, it MUST be stripped off
// together with the fragment delimiter character "#".
// The WebFinger [ID.ietfappsawgwebfinger] Resource in this case is the
// resulting URI, and the WebFinger Host is the authority component.
//
// Note: Since the definition of authority in RFC 3986 [RFC3986] is
// [ userinfo "@" ] host [ ":" port ], it is legal to have a user input
// identifier like userinfo@host:port, e.g., alice@example.com:8080.
const PORT = /^\d+$/;
function hasScheme(input) {
if (input.includes('://')) return true;
const authority = input.replace(/(\/|\?)/g, '#').split('#')[0];
if (authority.includes(':')) {
const index = authority.indexOf(':');
const hostOrPort = authority.slice(index + 1);
if (!PORT.test(hostOrPort)) {
return true;
}
}
return false;
}
function acctSchemeAssumed(input) {
if (!input.includes('@')) return false;
const parts = input.split('@');
const host = parts[parts.length - 1];
return !(host.includes(':') || host.includes('/') || host.includes('?'));
}
function normalize(input) {
if (typeof input !== 'string') {
throw new TypeError('input must be a string');
}
let output;
if (hasScheme(input)) {
output = input;
} else if (acctSchemeAssumed(input)) {
output = `acct:${input}`;
} else {
output = `https://${input}`;
}
return output.split('#')[0];
}
module.exports = normalize;

25
node_modules/openid-client/lib/index.js generated vendored Normal file
View File

@ -0,0 +1,25 @@
const Issuer = require('./issuer');
const { OPError, RPError } = require('./errors');
const Registry = require('./issuer_registry');
const Strategy = require('./passport_strategy');
const TokenSet = require('./token_set');
const { CLOCK_TOLERANCE, HTTP_OPTIONS } = require('./helpers/consts');
const generators = require('./helpers/generators');
const { setDefaults } = require('./helpers/request');
module.exports = {
Issuer,
Registry,
Strategy,
TokenSet,
errors: {
OPError,
RPError,
},
custom: {
setHttpOptionsDefaults: setDefaults,
http_options: HTTP_OPTIONS,
clock_tolerance: CLOCK_TOLERANCE,
},
generators,
};

10
node_modules/openid-client/lib/index.mjs generated vendored Normal file
View File

@ -0,0 +1,10 @@
import mod from './index.js';
export default mod;
export const Issuer = mod.Issuer;
export const Registry = mod.Registry;
export const Strategy = mod.Strategy;
export const TokenSet = mod.TokenSet;
export const errors = mod.errors;
export const custom = mod.custom;
export const generators = mod.generators;

282
node_modules/openid-client/lib/issuer.js generated vendored Normal file
View File

@ -0,0 +1,282 @@
/* eslint-disable max-classes-per-file */
const { inspect } = require('util');
const url = require('url');
const AggregateError = require('aggregate-error');
const jose = require('jose');
const LRU = require('lru-cache');
const objectHash = require('object-hash');
const { RPError } = require('./errors');
const getClient = require('./client');
const registry = require('./issuer_registry');
const processResponse = require('./helpers/process_response');
const webfingerNormalize = require('./helpers/webfinger_normalize');
const instance = require('./helpers/weak_cache');
const request = require('./helpers/request');
const { assertIssuerConfiguration } = require('./helpers/assert');
const {
ISSUER_DEFAULTS, OIDC_DISCOVERY, OAUTH2_DISCOVERY, WEBFINGER, REL, AAD_MULTITENANT_DISCOVERY,
} = require('./helpers/consts');
const AAD_MULTITENANT = Symbol('AAD_MULTITENANT');
class Issuer {
/**
* @name constructor
* @api public
*/
constructor(meta = {}) {
const aadIssValidation = meta[AAD_MULTITENANT];
delete meta[AAD_MULTITENANT];
['introspection', 'revocation'].forEach((endpoint) => {
// if intro/revocation endpoint auth specific meta is missing use the token ones if they
// are defined
if (
meta[`${endpoint}_endpoint`]
&& meta[`${endpoint}_endpoint_auth_methods_supported`] === undefined
&& meta[`${endpoint}_endpoint_auth_signing_alg_values_supported`] === undefined
) {
if (meta.token_endpoint_auth_methods_supported) {
meta[`${endpoint}_endpoint_auth_methods_supported`] = meta.token_endpoint_auth_methods_supported;
}
if (meta.token_endpoint_auth_signing_alg_values_supported) {
meta[`${endpoint}_endpoint_auth_signing_alg_values_supported`] = meta.token_endpoint_auth_signing_alg_values_supported;
}
}
});
Object.entries(meta).forEach(([key, value]) => {
instance(this).get('metadata').set(key, value);
if (!this[key]) {
Object.defineProperty(this, key, {
get() { return instance(this).get('metadata').get(key); },
enumerable: true,
});
}
});
instance(this).set('cache', new LRU({ max: 100 }));
registry.set(this.issuer, this);
const Client = getClient(this, aadIssValidation);
Object.defineProperties(this, {
Client: { value: Client },
FAPIClient: { value: class FAPIClient extends Client {} },
});
}
/**
* @name keystore
* @api public
*/
async keystore(reload = false) {
assertIssuerConfiguration(this, 'jwks_uri');
const keystore = instance(this).get('keystore');
const cache = instance(this).get('cache');
if (reload || !keystore) {
cache.reset();
const response = await request.call(this, {
method: 'GET',
responseType: 'json',
url: this.jwks_uri,
});
const jwks = processResponse(response);
const joseKeyStore = jose.JWKS.asKeyStore(jwks, { ignoreErrors: true });
cache.set('throttle', true, 60 * 1000);
instance(this).set('keystore', joseKeyStore);
return joseKeyStore;
}
return keystore;
}
/**
* @name queryKeyStore
* @api private
*/
async queryKeyStore({
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 && keys.length > 1 && !kid) {
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 new jose.JWKS.KeyStore(keys);
}
/**
* @name metadata
* @api public
*/
get metadata() {
const copy = {};
instance(this).get('metadata').forEach((value, key) => {
copy[key] = value;
});
return copy;
}
/**
* @name webfinger
* @api public
*/
static async webfinger(input) {
const resource = webfingerNormalize(input);
const { host } = url.parse(resource);
const webfingerUrl = `https://${host}${WEBFINGER}`;
const response = await request.call(this, {
method: 'GET',
url: webfingerUrl,
responseType: 'json',
searchParams: { resource, rel: REL },
followRedirect: true,
});
const body = processResponse(response);
const location = Array.isArray(body.links) && body.links.find((link) => typeof link === 'object' && link.rel === REL && link.href);
if (!location) {
throw new RPError({
message: 'no issuer found in webfinger response',
body,
});
}
if (typeof location.href !== 'string' || !location.href.startsWith('https://')) {
throw new RPError({
printf: ['invalid issuer location %s', location.href],
body,
});
}
const expectedIssuer = location.href;
if (registry.has(expectedIssuer)) {
return registry.get(expectedIssuer);
}
const issuer = await this.discover(expectedIssuer);
if (issuer.issuer !== expectedIssuer) {
registry.delete(issuer.issuer);
throw new RPError('discovered issuer mismatch, expected %s, got: %s', expectedIssuer, issuer.issuer);
}
return issuer;
}
/**
* @name discover
* @api public
*/
static async discover(uri) {
const parsed = url.parse(uri);
if (parsed.pathname.includes('/.well-known/')) {
const response = await request.call(this, {
method: 'GET',
responseType: 'json',
url: uri,
});
const body = processResponse(response);
return new Issuer({
...ISSUER_DEFAULTS,
...body,
[AAD_MULTITENANT]: !!AAD_MULTITENANT_DISCOVERY.find(
(discoveryURL) => uri.startsWith(discoveryURL),
),
});
}
const pathnames = [];
if (parsed.pathname.endsWith('/')) {
pathnames.push(`${parsed.pathname}${OIDC_DISCOVERY.substring(1)}`);
} else {
pathnames.push(`${parsed.pathname}${OIDC_DISCOVERY}`);
}
if (parsed.pathname === '/') {
pathnames.push(`${OAUTH2_DISCOVERY}`);
} else {
pathnames.push(`${OAUTH2_DISCOVERY}${parsed.pathname}`);
}
const errors = [];
// eslint-disable-next-line no-restricted-syntax
for (const pathname of pathnames) {
try {
const wellKnownUri = url.format({ ...parsed, pathname });
// eslint-disable-next-line no-await-in-loop
const response = await request.call(this, {
method: 'GET',
responseType: 'json',
url: wellKnownUri,
});
const body = processResponse(response);
return new Issuer({
...ISSUER_DEFAULTS,
...body,
[AAD_MULTITENANT]: !!AAD_MULTITENANT_DISCOVERY.find(
(discoveryURL) => wellKnownUri.startsWith(discoveryURL),
),
});
} catch (err) {
errors.push(err);
}
}
const err = new AggregateError(errors);
err.message = `Issuer.discover() failed.${err.message.split('\n')
.filter((line) => !line.startsWith(' at')).join('\n')}`;
throw err;
}
/* istanbul ignore next */
[inspect.custom]() {
return `${this.constructor.name} ${inspect(this.metadata, {
depth: Infinity,
colors: process.stdout.isTTY,
compact: false,
sorted: true,
})}`;
}
}
module.exports = Issuer;

3
node_modules/openid-client/lib/issuer_registry.js generated vendored Normal file
View File

@ -0,0 +1,3 @@
const REGISTRY = new Map();
module.exports = REGISTRY;

188
node_modules/openid-client/lib/passport_strategy.js generated vendored Normal file
View File

@ -0,0 +1,188 @@
/* eslint-disable no-underscore-dangle */
const url = require('url');
const { format } = require('util');
const cloneDeep = require('./helpers/deep_clone');
const { RPError, OPError } = require('./errors');
const { BaseClient } = require('./client');
const { random, codeChallenge } = require('./helpers/generators');
const pick = require('./helpers/pick');
const { resolveResponseType, resolveRedirectUri } = require('./helpers/client');
function verified(err, user, info = {}) {
if (err) {
this.error(err);
} else if (!user) {
this.fail(info);
} else {
this.success(user, info);
}
}
/**
* @name constructor
* @api public
*/
function OpenIDConnectStrategy({
client,
params = {},
passReqToCallback = false,
sessionKey,
usePKCE = true,
extras = {},
} = {}, verify) {
if (!(client instanceof BaseClient)) {
throw new TypeError('client must be an instance of openid-client Client');
}
if (typeof verify !== 'function') {
throw new TypeError('verify callback must be a function');
}
if (!client.issuer || !client.issuer.issuer) {
throw new TypeError('client must have an issuer with an identifier');
}
this._client = client;
this._issuer = client.issuer;
this._verify = verify;
this._passReqToCallback = passReqToCallback;
this._usePKCE = usePKCE;
this._key = sessionKey || `oidc:${url.parse(this._issuer.issuer).hostname}`;
this._params = cloneDeep(params);
this._extras = cloneDeep(extras);
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) {
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 && 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 {
this._usePKCE = 'S256';
}
} else if (typeof this._usePKCE === 'string' && !['plain', 'S256'].includes(this._usePKCE)) {
throw new TypeError(`${this._usePKCE} is not valid/implemented PKCE code_challenge_method`);
}
this.name = url.parse(client.issuer.issuer).hostname;
}
OpenIDConnectStrategy.prototype.authenticate = function authenticate(req, options) {
(async () => {
const client = this._client;
if (!req.session) {
throw new TypeError('authentication requires session support');
}
const reqParams = client.callbackParams(req);
const sessionKey = this._key;
/* start authentication request */
if (Object.keys(reqParams).length === 0) {
// provide options object with extra authentication parameters
const params = {
state: random(),
...this._params,
...options,
};
if (!params.nonce && params.response_type.includes('id_token')) {
params.nonce = random();
}
req.session[sessionKey] = pick(params, 'nonce', 'state', 'max_age', 'response_type');
if (this._usePKCE && params.response_type.includes('code')) {
const verifier = random();
req.session[sessionKey].code_verifier = verifier;
switch (this._usePKCE) { // eslint-disable-line default-case
case 'S256':
params.code_challenge = codeChallenge(verifier);
params.code_challenge_method = 'S256';
break;
case 'plain':
params.code_challenge = verifier;
break;
}
}
this.redirect(client.authorizationUrl(params));
return;
}
/* end authentication request */
/* start authentication response */
const session = req.session[sessionKey];
if (Object.keys(session || {}).length === 0) {
throw new Error(format('did not find expected authorization request details in session, req.session["%s"] is %j', sessionKey, session));
}
const {
state, nonce, max_age: maxAge, code_verifier: codeVerifier, response_type: responseType,
} = session;
try {
delete req.session[sessionKey];
} catch (err) {}
const opts = {
redirect_uri: this._params.redirect_uri,
...options,
};
const checks = {
state,
nonce,
max_age: maxAge,
code_verifier: codeVerifier,
response_type: responseType,
};
const tokenset = await client.callback(opts.redirect_uri, reqParams, checks, this._extras);
const passReq = this._passReqToCallback;
const loadUserinfo = this._verify.length > (passReq ? 3 : 2) && client.issuer.userinfo_endpoint;
const args = [tokenset, verified.bind(this)];
if (loadUserinfo) {
if (!tokenset.access_token) {
throw new RPError({
message: 'expected access_token to be returned when asking for userinfo in verify callback',
tokenset,
});
}
const userinfo = await client.userinfo(tokenset);
args.splice(1, 0, userinfo);
}
if (passReq) {
args.unshift(req);
}
this._verify(...args);
/* end authentication response */
})().catch((error) => {
if (
(error instanceof OPError && error.error !== 'server_error' && !error.error.startsWith('invalid'))
|| error instanceof RPError
) {
this.fail(error);
} else {
this.error(error);
}
});
};
module.exports = OpenIDConnectStrategy;

50
node_modules/openid-client/lib/token_set.js generated vendored Normal file
View File

@ -0,0 +1,50 @@
const base64url = require('./helpers/base64url');
const now = require('./helpers/unix_timestamp');
class TokenSet {
/**
* @name constructor
* @api public
*/
constructor(values) {
Object.assign(this, values);
}
/**
* @name expires_in=
* @api public
*/
set expires_in(value) { // eslint-disable-line camelcase
this.expires_at = now() + Number(value);
}
/**
* @name expires_in
* @api public
*/
get expires_in() { // eslint-disable-line camelcase
return Math.max.apply(null, [this.expires_at - now(), 0]);
}
/**
* @name expired
* @api public
*/
expired() {
return this.expires_in === 0;
}
/**
* @name claims
* @api public
*/
claims() {
if (!this.id_token) {
throw new TypeError('id_token not present in TokenSet');
}
return JSON.parse(base64url.decode(this.id_token.split('.')[1]));
}
}
module.exports = TokenSet;

121
node_modules/openid-client/package.json generated vendored Normal file
View File

@ -0,0 +1,121 @@
{
"name": "openid-client",
"version": "4.9.1",
"description": "OpenID Connect Relying Party (RP, Client) implementation for Node.js runtime, supports passportjs",
"keywords": [
"auth",
"authentication",
"basic",
"certified",
"client",
"connect",
"dynamic",
"electron",
"hybrid",
"identity",
"implicit",
"oauth",
"oauth2",
"oidc",
"openid",
"passport",
"relying party",
"strategy"
],
"homepage": "https://github.com/panva/node-openid-client",
"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": [
"lib",
"types/index.d.ts"
],
"scripts": {
"coverage": "nyc mocha test/**/*.test.js",
"lint": "eslint lib test",
"lint-fix": "eslint lib test --fix",
"test": "mocha test/**/*.test.js"
},
"nyc": {
"reporter": [
"lcov",
"text-summary"
]
},
"dependencies": {
"aggregate-error": "^3.1.0",
"got": "^11.8.0",
"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"
},
"devDependencies": {
"@types/passport": "^1.0.4",
"base64url": "^3.0.1",
"chai": "^4.2.0",
"eslint": "^7.12.1",
"eslint-config-airbnb-base": "^14.2.0",
"eslint-plugin-import": "^2.22.1",
"mocha": "^8.2.0",
"nock": "^13.0.2",
"nyc": "^15.1.0",
"readable-mock-req": "^0.2.2",
"sinon": "^9.2.0",
"timekeeper": "^2.2.0"
},
"engines": {
"node": "^10.19.0 || >=12.0.0 < 13 || >=13.7.0 < 14 || >= 14.2.0"
},
"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",
"section": "Performance",
"hidden": false
},
{
"type": "test",
"hidden": true
}
]
}
}

968
node_modules/openid-client/types/index.d.ts generated vendored Normal file
View File

@ -0,0 +1,968 @@
/// <reference types="node" />
/// <reference lib="dom"/>
// TypeScript Version: 3.6
/**
* @see https://github.com/panva/node-openid-client/blob/master/docs/README.md
*/
import * as http from "http";
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 RetryFunction = (retry: number, error: Error) => number;
export type CustomHttpOptionsProvider = (options: HttpOptions) => HttpOptions;
export type TokenTypeHint = "access_token" | "refresh_token" | string;
export type DPoPInput =
| crypto.KeyObject
| crypto.PrivateKeyInput
| jose.JWKRSAKey
| jose.JWKECKey
| jose.JWKOKPKey;
interface UnknownObject {
[key: string]: unknown;
}
/**
* @see https://github.com/panva/node-openid-client/blob/master/lib/index.js
*/
export const custom: {
setHttpOptionsDefaults(params: HttpOptions): undefined;
readonly http_options: unique symbol;
readonly clock_tolerance: unique symbol;
};
/**
* @see https://medium.com/@darutk/diagrams-of-all-the-openid-connect-flows-6968e3990660
*/
export type ResponseType =
| "code"
| "id_token"
| "code id_token"
| "id_token token"
| "code token"
| "code id_token token"
| "none";
/**
* @see https://github.com/panva/node-openid-client/blob/master/docs/README.md#client-authentication-methods
*/
export type ClientAuthMethod =
| "client_secret_basic"
| "client_secret_post"
| "client_secret_jwt"
| "private_key_jwt"
| "tls_client_auth"
| "self_signed_tls_client_auth"
| "none";
/**
* @see https://github.com/panva/node-openid-client/blob/master/docs/README.md#new-clientmetadata-jwks
*/
export interface ClientMetadata {
// important
client_id: string;
id_token_signed_response_alg?: string;
token_endpoint_auth_method?: ClientAuthMethod;
client_secret?: string;
redirect_uris?: string[];
response_types?: ResponseType[];
post_logout_redirect_uris?: string[];
default_max_age?: number;
require_auth_time?: boolean;
tls_client_certificate_bound_access_tokens?: boolean;
request_object_signing_alg?: string;
// less important
id_token_encrypted_response_alg?: string;
id_token_encrypted_response_enc?: string;
introspection_endpoint_auth_method?: ClientAuthMethod;
introspection_endpoint_auth_signing_alg?: string;
request_object_encryption_alg?: string;
request_object_encryption_enc?: string;
revocation_endpoint_auth_method?: ClientAuthMethod;
revocation_endpoint_auth_signing_alg?: string;
token_endpoint_auth_signing_alg?: string;
userinfo_encrypted_response_alg?: string;
userinfo_encrypted_response_enc?: string;
userinfo_signed_response_alg?: string;
authorization_encrypted_response_alg?: string;
authorization_encrypted_response_enc?: string;
authorization_signed_response_alg?: string;
[key: string]: unknown;
}
export interface ClaimsParameterMember {
essential?: boolean;
value?: string;
values?: string[];
[key: string]: unknown;
}
export interface AuthorizationParameters {
acr_values?: string;
audience?: string;
claims?:
| string
| {
id_token?: {
[key: string]: null | ClaimsParameterMember;
};
userinfo?: {
[key: string]: null | ClaimsParameterMember;
};
};
claims_locales?: string;
client_id?: string;
code_challenge_method?: string;
code_challenge?: string;
display?: string;
id_token_hint?: string;
login_hint?: string;
max_age?: number;
nonce?: string;
prompt?: string;
redirect_uri?: string;
registration?: string;
request_uri?: string;
request?: string;
resource?: string | string[];
response_mode?: string;
response_type?: string;
scope?: string;
state?: string;
ui_locales?: string;
[key: string]: unknown;
}
export interface EndSessionParameters {
id_token_hint?: TokenSet | string;
post_logout_redirect_uri?: string;
state?: string;
[key: string]: unknown;
}
export interface CallbackParamsType {
access_token?: string;
code?: string;
error?: string;
error_description?: string;
error_uri?: string;
expires_in?: string;
id_token?: string;
state?: string;
token_type?: string;
session_state?: string;
response?: string;
[key: string]: unknown;
}
export interface OAuthCallbackChecks {
/**
* When provided the authorization response will be checked for presence of required parameters for a
* given response_type. Use of this check is recommended.
*/
response_type?: string;
/**
* When provided the authorization response's state parameter will be checked to be the this expected one.
* Use of this check is required if you sent a state parameter into an authorization request.
*/
state?: string;
/**
* PKCE code_verifier to be sent to the token endpoint during code exchange. Use of this check is required
* if you sent a code_challenge parameter into an authorization request.
*/
code_verifier?: string;
/**
* This must be set to true when requesting JARM responses.
*/
jarm?: boolean;
}
export interface OpenIDCallbackChecks extends OAuthCallbackChecks {
/**
* When provided the authorization response's ID Token auth_time parameter will be checked to be conform to the
* max_age value. Use of this check is required if you sent a max_age parameter into an authorization request.
*/
max_age?: number;
/**
* When provided the authorization response's ID Token nonce parameter will be checked to be the this expected
* one. Use of this check is required if you sent a nonce parameter into an authorization request.
*/
nonce?: string;
}
export interface CallbackExtras {
/**
* extra request body properties to be sent to the AS during code exchange.
*/
exchangeBody?: object;
/**
* extra client assertion payload parameters to be sent as part of a client JWT assertion. This is only used
* when the client's token_endpoint_auth_method is either client_secret_jwt or private_key_jwt.
*/
clientAssertionPayload?: object;
/**
* Private key to sign the DPoP Proof JWT with. This can be a crypto.KeyObject, crypto.createPrivateKey valid
* inputs, or a JWK formatted private key.
*/
DPoP?: DPoPInput;
}
export interface RefreshExtras {
/**
* extra request body properties to be sent to the AS during refresh token exchange.
*/
exchangeBody?: object;
/**
* extra client assertion payload parameters to be sent as part of a client JWT assertion.
* This is only used when the client's token_endpoint_auth_method is either client_secret_jwt or private_key_jwt.
*/
clientAssertionPayload?: object;
/**
* Private key to sign the DPoP Proof JWT with. This can be a crypto.KeyObject, crypto.createPrivateKey valid
* inputs, or a JWK formatted private key.
*/
DPoP?: DPoPInput;
}
export interface GrantBody {
grant_type: string;
[key: string]: unknown;
}
export interface GrantExtras {
/**
* extra client assertion payload parameters to be sent as part of a client JWT assertion.
* This is only used when the client's token_endpoint_auth_method is either client_secret_jwt or private_key_jwt.
*/
clientAssertionPayload?: object;
/**
* Private key to sign the DPoP Proof JWT with. This can be a crypto.KeyObject, crypto.createPrivateKey valid
* inputs, or a JWK formatted private key.
*/
DPoP?: DPoPInput;
}
export interface IntrospectExtras {
/**
* extra request body properties to be sent to the introspection endpoint.
*/
introspectBody?: object;
/**
* extra client assertion payload parameters to be sent as part of a client JWT assertion.
* This is only used when the client's token_endpoint_auth_method is either client_secret_jwt or private_key_jwt.
*/
clientAssertionPayload?: object;
}
export interface RevokeExtras {
/**
* extra request body properties to be sent to the revocation endpoint.
*/
revokeBody?: object;
/**
* extra client assertion payload parameters to be sent as part of a client JWT assertion.
* This is only used when the client's token_endpoint_auth_method is either client_secret_jwt or private_key_jwt.
*/
clientAssertionPayload?: object;
}
export interface RequestObjectPayload extends AuthorizationParameters {
client_id?: string;
iss?: string;
aud?: string;
iat?: number;
exp?: number;
jti?: string;
[key: string]: unknown;
}
export interface RegisterOther {
/**
* JWK Set formatted object with private keys used for signing client assertions or decrypting responses.
* When neither jwks_uri or jwks is present in metadata the key's public parts will be registered as jwks.
*/
jwks?: jose.JSONWebKeySet;
/**
* Initial Access Token to use as a Bearer token during the registration call.
*/
initialAccessToken?: string;
}
export interface DeviceAuthorizationParameters {
client_id?: string;
scope?: string;
[key: string]: unknown;
}
export interface DeviceAuthorizationExtras {
/**
* extra request body properties to be sent to the AS during the Device Access Token Request
*/
exchangeBody?: object;
/**
* extra client assertion payload parameters to be sent as part of a client JWT assertion.
* This is only used when the client's token_endpoint_auth_method is either client_secret_jwt or private_key_jwt.
*/
clientAssertionPayload?: object;
/**
* Private key to sign the DPoP Proof JWT with. This can be a crypto.KeyObject, crypto.createPrivateKey valid
* inputs, or a JWK formatted private key.
*/
DPoP?: DPoPInput;
}
export interface PushedAuthorizationRequestExtras {
clientAssertionPayload?: object;
}
export type Address<ExtendedAddress extends {} = UnknownObject> = Override<
{
formatted?: string;
street_address?: string;
locality?: string;
region?: string;
postal_code?: string;
country?: string;
},
ExtendedAddress
>;
export type UserinfoResponse<
UserInfo extends {} = UnknownObject,
ExtendedAddress extends {} = UnknownObject
> = Override<
{
sub: string;
name?: string;
given_name?: string;
family_name?: string;
middle_name?: string;
nickname?: string;
preferred_username?: string;
profile?: string;
picture?: string;
website?: string;
email?: string;
email_verified?: boolean;
gender?: string;
birthdate?: string;
zoneinfo?: string;
locale?: string;
phone_number?: string;
updated_at?: number;
address?: Address<ExtendedAddress>;
},
UserInfo
>;
export interface IntrospectionResponse {
active: boolean;
client_id?: string;
exp?: number;
iat?: number;
sid?: string;
iss?: string;
jti?: string;
username?: string;
aud?: string | string[];
scope: string;
sub?: string;
nbf?: number;
token_type?: string;
cnf?: {
"x5t#S256"?: string;
[key: string]: unknown;
};
[key: string]: unknown;
}
export interface ClientOptions {
additionalAuthorizedParties?: string | string[];
}
/**
* Encapsulates a dynamically registered, discovered or instantiated OpenID Connect Client (Client),
* Relying Party (RP), and its metadata, its instances hold the methods for getting an authorization URL,
* consuming callbacks, triggering token endpoint grants, revoking and introspecting tokens.
*/
export class Client {
constructor(
metadata: ClientMetadata,
jwks?: jose.JSONWebKeySet,
options?: ClientOptions
);
[custom.http_options]: CustomHttpOptionsProvider;
[custom.clock_tolerance]: number;
metadata: ClientMetadata;
issuer: Issuer<this>;
static issuer: Issuer<Client>;
/**
* Returns the target authorization redirect URI to redirect End-Users to using the provided parameters.
* @param parameters Authorization Request parameters
*/
authorizationUrl(parameters?: AuthorizationParameters): string;
/**
* Returns the target logout redirect URI to redirect End-Users to using the provided parameters.
* @param parameters RP-Initiated Logout Request parameters
*/
endSessionUrl(parameters?: EndSessionParameters): string;
/**
* Returns recognized callback parameters from a provided input.
*
* - When input is of type string it will be parsed using url.parse and its query component will be returned
* - When input is a GET http/http2 request object its url property will be parsed using url.parse and its
* query component will be returned
* - When input is a POST http/http2 request object its body property will be parsed or returned if it is already
* an object. Note: the request read stream will not be parsed, it is expected that you will have a body parser
* prior to calling this method. This parser would set the req.body property
*/
callbackParams(
input: string | http.IncomingMessage | http2.Http2ServerRequest
): CallbackParamsType;
/**
* Performs the callback for Authorization Server's authorization response.
* @param redirectUri redirect_uri used for the authorization request
* @param parameters returned authorization response, see client.callbackParams if you need help getting them.
* @param checks checks to perform on the Authorization Response
* @param extras add extra parameters to the Token Endpoint Request and/or Client Authentication JWT Assertion
*/
callback(
redirectUri: string | undefined,
parameters: CallbackParamsType,
checks?: OpenIDCallbackChecks,
extras?: CallbackExtras
): Promise<TokenSet>;
/**
* Pure OAuth 2.0 version of callback().
* @param redirectUri redirect_uri used for the authorization request
* @param parameters returned authorization response, see client.callbackParams if you need help getting them.
* @param checks checks to perform on the Authorization Response
* @param extras add extra parameters to the Token Endpoint Request and/or Client Authentication JWT Assertion
*/
oauthCallback(
redirectUri: string | undefined,
parameters: CallbackParamsType,
checks?: OAuthCallbackChecks,
extras?: CallbackExtras
): Promise<TokenSet>;
/**
* Performs refresh_token grant type exchange.
* @param refreshToken Refresh Token value. When TokenSet instance is provided its refresh_token property
* will be used automatically.
* @param extras Add extra parameters to the Token Endpoint Request and/or Client Authentication JWT Assertion
*/
refresh(
refreshToken: TokenSet | string,
extras?: RefreshExtras
): Promise<TokenSet>;
/**
* Fetches the OIDC userinfo response with the provided Access Token. Also handles signed and/or
* encrypted userinfo responses. When TokenSet is provided as an argument the userinfo sub property
* will also be checked to match the on in the TokenSet's ID Token.
*
* @param accessToken Access Token value. When TokenSet instance is provided its access_token property
* will be used automatically.
* @param options Options for the UserInfo request.
*/
userinfo<
TUserInfo extends {} = UnknownObject,
TAddress extends {} = UnknownObject
>(
accessToken: TokenSet | string,
options?: {
method?: "GET" | "POST";
via?: "header" | "body" | "query";
tokenType?: string;
params?: object;
DPoP?: DPoPInput;
}
): Promise<UserinfoResponse<TUserInfo, TAddress>>;
/**
* Fetches an arbitrary resource with the provided Access Token in an Authorization header.
*
* @param resourceUrl Resource URL to request a response from.
* @param accessToken Access Token value. When TokenSet instance is provided its access_token property
* will be used automatically.
* @param options Options for the request.
*/
requestResource(
resourceUrl: string | URL,
accessToken: TokenSet | string,
options?: {
headers?: object;
body?: string | Buffer;
method?: "GET" | "POST" | "PUT" | "HEAD" | "DELETE" | "OPTIONS" | "TRACE" | "PATCH";
tokenType?: string;
DPoP?: DPoPInput;
}
): CancelableRequest<Response<Buffer>>;
/**
* Performs an arbitrary grant_type exchange at the token_endpoint.
*/
grant(body: GrantBody, extras?: GrantExtras): Promise<TokenSet>;
/**
* Introspects a token at the Authorization Server's introspection_endpoint.
*/
introspect(
token: string,
tokenTypeHint?: TokenTypeHint,
extras?: IntrospectExtras
): Promise<IntrospectionResponse>;
/**
* Revokes a token at the Authorization Server's revocation_endpoint.
*/
revoke(
token: string,
tokenTypeHint?: TokenTypeHint,
extras?: RevokeExtras
): Promise<undefined>;
/**
* Creates a signed and optionally encrypted Request Object to send to the AS. Uses the client's
* request_object_signing_alg, request_object_encryption_alg, request_object_encryption_enc metadata for
* determining the algorithms to use.
*/
requestObject(payload: RequestObjectPayload): Promise<string>;
/**
* Starts a Device Authorization Request at the issuer's device_authorization_endpoint and returns a handle
* for subsequent Device Access Token Request polling.
*/
deviceAuthorization(
parameters?: DeviceAuthorizationParameters,
extras?: DeviceAuthorizationExtras
): Promise<DeviceFlowHandle<Client>>;
pushedAuthorizationRequest(
parameters?: AuthorizationParameters,
extras?: PushedAuthorizationRequestExtras,
): Promise<{
request_uri: string;
expires_in: number;
[key: string]: unknown;
}>;
static register(
metadata: object,
other?: RegisterOther & ClientOptions
): Promise<Client>;
static fromUri(
registrationClientUri: string,
registrationAccessToken: string,
jwks?: jose.JSONWebKeySet,
clientOptions?: ClientOptions
): Promise<Client>;
static [custom.http_options]: CustomHttpOptionsProvider;
[key: string]: unknown;
}
interface DeviceFlowPollOptions {
signal?: AbortSignal,
}
export class DeviceFlowHandle<TClient extends Client> {
// tslint:disable-line:no-unnecessary-generics
poll(options?: DeviceFlowPollOptions): Promise<TokenSet>;
abort(): void;
expired(): boolean;
expires_at: number;
client: TClient;
user_code: string;
device_code: string;
verification_uri: string;
verification_uri_complete: string;
expires_in: number;
}
export interface IssuerMetadata {
issuer: string;
authorization_endpoint?: string;
token_endpoint?: string;
jwks_uri?: string;
userinfo_endpoint?: string;
revocation_endpoint?: string;
end_session_endpoint?: string;
registration_endpoint?: string;
token_endpoint_auth_methods_supported?: string[];
token_endpoint_auth_signing_alg_values_supported?: string[];
introspection_endpoint_auth_methods_supported?: string[];
introspection_endpoint_auth_signing_alg_values_supported?: string[];
revocation_endpoint_auth_methods_supported?: string[];
revocation_endpoint_auth_signing_alg_values_supported?: string[];
request_object_signing_alg_values_supported?: string[];
mtls_endpoint_aliases?: MtlsEndpointAliases;
[key: string]: unknown;
}
export interface MtlsEndpointAliases {
token_endpoint?: string;
userinfo_endpoint?: string;
revocation_endpoint?: string;
introspection_endpoint?: string;
device_authorization_endpoint?: string;
}
// https://stackoverflow.com/questions/40249906/using-a-generic-type-argument-with-typeof-t
// https://stackoverflow.com/questions/39622778/what-is-new-in-typescript
// https://github.com/Microsoft/TypeScript/issues/204
export interface TypeOfGenericClient<TClient extends Client> {
new (
metadata: ClientMetadata,
jwks?: jose.JSONWebKeySet,
options?: ClientOptions
): TClient;
[custom.http_options]: CustomHttpOptionsProvider;
[custom.clock_tolerance]: number;
}
/**
* Encapsulates a discovered or instantiated OpenID Connect Issuer (Issuer), Identity Provider (IdP),
* Authorization Server (AS) and its metadata.
*/
export class Issuer<TClient extends Client> {
// tslint:disable-line:no-unnecessary-generics
constructor(metadata: IssuerMetadata);
/**
* Returns the <Client> class tied to this issuer.
*/
Client: TypeOfGenericClient<TClient>;
/**
* Returns the <FAPIClient> class tied to this issuer.
*/
FAPIClient: TypeOfGenericClient<TClient>;
/**
* Returns metadata from the issuer's discovery document.
*/
metadata: IssuerMetadata;
[custom.http_options]: CustomHttpOptionsProvider;
/**
* Returns the issuer's jwks_uri keys as a `jose` parsed JWKS.Keystore.
* @param forceReload forces a reload of the issuer's jwks_uri
*/
keystore(forceReload?: boolean): Promise<jose.JWKS.KeyStore>;
/**
* Loads OpenID Connect 1.0 and/or OAuth 2.0 Authorization Server Metadata documents.
* When the issuer argument contains '.well-known' only that document is loaded, otherwise
* performs both openid-configuration and oauth-authorization-server requests.
* @param issuer Issuer Identifier or metadata URL
*/
static discover(issuer: string): Promise<Issuer<Client>>;
/**
* Performs OpenID Provider Issuer Discovery based on End-User input.
* @param input EMAIL, URL, Hostname and Port, acct or syntax input
*/
static webfinger(input: string): Promise<Issuer<Client>>;
static [custom.http_options]: CustomHttpOptionsProvider;
[key: string]: unknown;
}
export interface TokenSetParameters {
/**
* The raw access token in JWT format
*/
access_token?: string;
/**
* Usually "Bearer"
*/
token_type?: string;
/**
* The raw id token in JWT format
*/
id_token?: string;
/**
* Refresh token, opaque string value
*/
refresh_token?: string;
/**
* space-separated scope(s) used for the authentication request
*/
scope?: string;
/**
* When the token set was received the expires_at field was calculated based on current timestamp
* and the expires_in. When recalling a TokenSet instance just the expires_at should be passed in.
*/
expires_at?: number;
/**
* State value passed in the authentication request
*/
session_state?: string;
[key: string]: unknown;
}
export interface IdTokenClaims extends UserinfoResponse {
acr?: string;
amr?: string[];
at_hash?: string;
aud: string | string[];
auth_time?: number;
azp?: string;
c_hash?: string;
exp: number;
iat: number;
iss: string;
nonce?: string;
s_hash?: string;
sub: string;
[key: string]: unknown;
}
/**
* Creates a new TokenSet from the provided response. E.g. parsed token endpoint response, parsed callback
* parameters. You only need to instantiate a TokenSet yourself if you recall it from e.g. distributed cache
* storage or a database. Note: manually constructed TokenSet instances do not undergo any validations.
*/
export class TokenSet implements TokenSetParameters {
access_token?: string;
token_type?: string;
id_token?: string;
refresh_token?: string;
expires_in?: number;
expires_at?: number;
session_state?: string;
scope?: string;
constructor(input?: TokenSetParameters);
/**
* Given that the instance has expires_at / expires_in this function returns true / false when the
* access token (which expires properties are for) is beyond its lifetime.
*/
expired(): boolean;
/**
* Given that the instance has an id_token this function returns its parsed payload object.
* Does not perform any validations as these were done prior to openid-client returning the
* tokenset in the first place.
*/
claims(): IdTokenClaims;
[key: string]: unknown;
}
export type StrategyVerifyCallbackUserInfo<
TUser,
TUserInfo extends {} = UnknownObject,
TAddress extends {} = UnknownObject
> = (
tokenset: TokenSet,
userinfo: UserinfoResponse<TUserInfo, TAddress>,
done: (err: any, user?: TUser) => void
) => void;
export type StrategyVerifyCallback<TUser> = (
tokenset: TokenSet,
done: (err: any, user?: TUser) => void
) => void;
export type StrategyVerifyCallbackReqUserInfo<
TUser,
TUserInfo extends {} = UnknownObject,
TAddress extends {} = UnknownObject
> = (
req: http.IncomingMessage,
tokenset: TokenSet,
userinfo: UserinfoResponse<TUserInfo, TAddress>,
done: (err: any, user?: TUser) => void
) => void;
export type StrategyVerifyCallbackReq<TUser> = (
req: http.IncomingMessage,
tokenset: TokenSet,
done: (err: any, user?: TUser) => void
) => void;
export interface StrategyOptions<TClient extends Client> {
client: TClient;
/**
* Authorization Request parameters. The strategy will use these.
*/
params?: AuthorizationParameters;
/**
* "extras" argument value passed to the client.callback() call.
*/
extras?: CallbackExtras;
/**
* Boolean specifying whether the verify function should get the request object as first argument instead.
*/
passReqToCallback?: boolean;
/**
* The PKCE method to use. When 'true' it will resolve based on the issuer metadata, when 'false' no PKCE will be
* used.
*/
usePKCE?: boolean | string;
/**
* The property name to store transaction information such as nonce, state, max_age, code_verifier, and response_type.
*/
sessionKey?: string;
}
// tslint:disable-next-line:no-unnecessary-class
export class Strategy<TUser, TClient extends Client> {
// tslint:disable-line:no-unnecessary-generics
constructor(
options: StrategyOptions<TClient>,
verify:
| StrategyVerifyCallback<TUser>
| StrategyVerifyCallbackUserInfo<TUser>
| StrategyVerifyCallbackReq<TUser>
| StrategyVerifyCallbackReqUserInfo<TUser>
);
authenticate(req: any, options?: any): void;
success(user: any, info?: any): void;
fail(challenge: any, status: number): void;
fail(status: number): void;
redirect(url: string, status?: number): void;
pass(): void;
error(err: Error): void;
}
/**
* @see https://github.com/panva/node-openid-client/blob/master/lib/helpers/generators.js
*/
export namespace generators {
/**
* Generates random bytes and encodes them in url safe base64.
* @param bytes Number indicating the number of bytes to generate.
*/
function random(bytes?: number): string;
/**
* Generates random bytes and encodes them in url safe base64.
* @param bytes Number indicating the number of bytes to generate.
*/
function state(bytes?: number): string;
/**
* Generates random bytes and encodes them in url safe base64.
* @param bytes Number indicating the number of bytes to generate.
*/
function nonce(bytes?: number): string;
/**
* Generates random bytes and encodes them in url safe base64.
* @param bytes Number indicating the number of bytes to generate.
*/
function codeVerifier(bytes?: number): string;
/**
* Calculates the S256 PKCE code challenge for an arbitrary code verifier.
* Encodes in url safe base64.
* @param verifier Code verifier to calculate the S256 code challenge for
*/
function codeChallenge(verifier: string): string;
}
/**
* @see https://github.com/panva/node-openid-client/blob/master/lib/errors.js
*/
export namespace errors {
/**
* Error class thrown when a regular OAuth 2.0 / OIDC style error is returned by the AS or an
* unexpected response is sent by the OP.
*/
class OPError extends Error {
/**
* The 'error_description' parameter from the AS response.
*/
error_description?: string;
/**
* The 'error' parameter from the AS response.
*/
error?: string;
/**
* The 'error_uri' parameter from the AS response.
*/
error_uri?: string;
/**
* The 'state' parameter from the AS response.
*/
state?: string;
/**
* The 'scope' parameter from the AS response.
*/
scope?: string;
/**
* The 'session_state' parameter from the AS response.
*/
session_state?: string;
/**
* When the error is related to an http(s) request this propetty will hold the response object
* from got.
*/
response?: any;
}
/**
* Error class thrown when client-side response expectations/validations fail to pass.
* Depending on the context it may or may not have additional context-based properties like
* checks, jwt, params or body.
*/
class RPError extends Error {
jwt?: string;
checks?: object;
params?: object;
body?: object;
/**
* When the error is related to an http(s) request this propetty will hold the response object
* from got.
*/
response?: any;
now?: number;
tolerance?: number;
nbf?: number;
exp?: number;
iat?: number;
auth_time?: number;
}
}
/**
* This is very useful to allow applications to override property types
* without making types in this package too weird
*/
// https://github.com/Microsoft/TypeScript/issues/25987#issuecomment-441224690
type KnownKeys<T> = {
[K in keyof T]: string extends K ? never : number extends K ? never : K;
} extends { [_ in keyof T]: infer U }
? {} extends U
? never
: U
: never;
type Override<T1, T2> = Omit<T1, keyof Omit<T2, keyof KnownKeys<T2>>> & T2;