+ * Fetch the server metadata from an authorization server's metadata endpoint.
+ * @param {URL} metadataUrl url
+ * @returns {Promise<Metadata>} metadata
+ */
+ async fetchMetadata(metadataUrl) {
+ const metadataResponse = await this.fetchJSON(metadataUrl);
+ const metadata = {};
+ if (metadataResponse) {
+ // Map snake_case fields to camelCase.
+ Object.entries({
+ issuer: 'issuer',
+ authorizationEndpoint: 'authorization_endpoint',
+ tokenEndpoint: 'token_endpoint',
+ ticketEndpoint: 'ticket_endpoint',
+ introspectionEndpoint: 'introspection_endpoint',
+ introspectionEndpointAuthMethodsSupported: 'introspection_endpoint_auth_methods_supported',
+ revocationEndpoint: 'revocation_endpoint',
+ revocationEndpointAuthMethodsSupported: 'revocation_endpoint_auth_methods_supported',
+ scopesSupported: 'scopes_supported',
+ responseTypesSupported: 'response_types_supported',
+ grantTypesSupported: 'grant_types_supported',
+ serviceDocumentation: 'service_documentation',
+ codeChallengeMethodsSupported: 'code_challenge_methods_supported',
+ authorizationResponseIssParameterSupported: 'authorization_response_iss_parameter_supported',
+ userinfoEndpoint: 'userinfo_endpoint',
+ }).forEach(([c, s]) => {
+ if (s in metadataResponse) {
+ metadata[c] = metadataResponse[s]; // eslint-disable-line security/detect-object-injection
+ }
+ });
+ }
+
+ return metadata;
+ }
+
+
+ /**
+ * POST to the auth endpoint, to redeem a code for a profile or token.
+ * N.B. this absorbs any errors!
+ * @param {URL} urlObj url
+ * @param {string} code code
+ * @param {string} codeVerifier verifier
+ * @param {string} clientId client id
+ * @param {string} redirectURI uri
+ * @returns {Promise<object>} response
+ */
+ async redeemCode(urlObj, code, codeVerifier, clientId, redirectURI) {
+ const _scope = _fileScope('redeemCode');
+
+ const postRedeemCodeConfig = {
+ url: urlObj,
+ method: 'POST',
+ headers: {
+ [Enum.Header.Accept]: this._jsonAccept,
+ },
+ form: {
+ 'grant_type': 'authorization_code',
+ code,
+ 'client_id': clientId,
+ 'redirect_uri': redirectURI,
+ 'code_verifier': codeVerifier,
+ },
+ responseType: 'json',
+ };
+
+ try {
+ const response = await this.got(postRedeemCodeConfig);
+ return response.body;
+ } catch (e) {
+ this.logger.error(_scope, 'redeem code request failed', { error: e, url: urlObj.href });
+ return;
+ }
+ }
+
+
+ /**
+ * Deprecated method name alias.
+ * @see redeemCode
+ * @param {URL} urlObj url
+ * @param {string} code code
+ * @param {string} codeVerifier verifier
+ * @param {string} clientId client id
+ * @param {string} redirectURI uri
+ * @returns {Promise<object>} response