UNPKG

@sphereon/oid4vci-client

Version:

OpenID for Verifiable Credential Issuance (OpenID4VCI) client

189 lines • 11.2 kB
"use strict"; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.MetadataClientV1_0_13 = void 0; const oid4vci_common_1 = require("@sphereon/oid4vci-common"); const debug_1 = __importDefault(require("debug")); const functions_1 = require("./functions"); const debug = (0, debug_1.default)('sphereon:oid4vci:metadata'); class MetadataClientV1_0_13 { /** * Retrieve metadata using the Initiation obtained from a previous step * * @param credentialOffer */ static retrieveAllMetadataFromCredentialOffer(credentialOffer) { return __awaiter(this, void 0, void 0, function* () { return MetadataClientV1_0_13.retrieveAllMetadataFromCredentialOfferRequest(credentialOffer.credential_offer); }); } /** * Retrieve the metada using the initiation request obtained from a previous step * @param request */ static retrieveAllMetadataFromCredentialOfferRequest(request) { return __awaiter(this, void 0, void 0, function* () { const issuer = (0, oid4vci_common_1.getIssuerFromCredentialOfferPayload)(request); if (issuer) { return MetadataClientV1_0_13.retrieveAllMetadata(issuer); } throw new Error("can't retrieve metadata from CredentialOfferRequest. No issuer field is present"); }); } /** * Retrieve all metadata from an issuer * @param issuer The issuer URL * @param opts */ static retrieveAllMetadata(issuer, opts) { return __awaiter(this, void 0, void 0, function* () { let token_endpoint; let credential_endpoint; let deferred_credential_endpoint; let authorization_endpoint; let authorization_challenge_endpoint; let authorizationServerType = 'OID4VCI'; let authorization_servers = [issuer]; const oid4vciResponse = yield MetadataClientV1_0_13.retrieveOpenID4VCIServerMetadata(issuer, { errorOnNotFound: false }); // We will handle errors later, given we will also try other metadata locations let credentialIssuerMetadata = oid4vciResponse === null || oid4vciResponse === void 0 ? void 0 : oid4vciResponse.successBody; if (credentialIssuerMetadata) { debug(`Issuer ${issuer} OID4VCI well-known server metadata\r\n${JSON.stringify(credentialIssuerMetadata)}`); credential_endpoint = credentialIssuerMetadata.credential_endpoint; deferred_credential_endpoint = credentialIssuerMetadata.deferred_credential_endpoint; if (credentialIssuerMetadata.token_endpoint) { token_endpoint = credentialIssuerMetadata.token_endpoint; } authorization_challenge_endpoint = credentialIssuerMetadata.authorization_challenge_endpoint; if (credentialIssuerMetadata.authorization_servers) { authorization_servers = credentialIssuerMetadata.authorization_servers; } } // No specific OID4VCI endpoint. Either can be an OAuth2 AS or an OIDC IDP. Let's start with OIDC first // TODO: for now we're taking just the first one let response = yield (0, functions_1.retrieveWellknown)(authorization_servers[0], oid4vci_common_1.WellKnownEndpoints.OPENID_CONFIGURATION, { errorOnNotFound: false, }); let authMetadata = response.successBody; if (authMetadata) { debug(`Issuer ${issuer} has OpenID Connect Server metadata in well-known location`); authorizationServerType = 'OIDC'; } else { // Now let's do OAuth2 // TODO: for now we're taking just the first one response = yield (0, functions_1.retrieveWellknown)(authorization_servers[0], oid4vci_common_1.WellKnownEndpoints.OAUTH_AS, { errorOnNotFound: false }); authMetadata = response.successBody; } if (!authMetadata) { // We will always throw an error, no matter whether the user provided the option not to, because this is bad. if (!authorization_servers.includes(issuer)) { throw Error(`Issuer ${issuer} provided a separate authorization server ${authorization_servers}, but that server did not provide metadata`); } } else { if (!authorizationServerType) { authorizationServerType = 'OAuth 2.0'; } debug(`Issuer ${issuer} has ${authorizationServerType} Server metadata in well-known location`); if (!authMetadata.authorization_endpoint) { console.warn(`Issuer ${issuer} of type ${authorizationServerType} has no authorization_endpoint! Will use ${authorization_endpoint}. This only works for pre-authorized flows`); } else if (authorization_endpoint && authMetadata.authorization_endpoint !== authorization_endpoint) { throw Error(`Credential issuer has a different authorization_endpoint (${authorization_endpoint}) from the Authorization Server (${authMetadata.authorization_endpoint})`); } authorization_endpoint = authMetadata.authorization_endpoint; if (authorization_challenge_endpoint && authMetadata.authorization_challenge_endpoint !== authorization_challenge_endpoint) { throw Error(`Credential issuer has a different authorization_challenge_endpoint (${authorization_challenge_endpoint}) from the Authorization Server (${authMetadata.authorization_challenge_endpoint})`); } authorization_challenge_endpoint = authMetadata.authorization_challenge_endpoint; if (!authMetadata.token_endpoint) { throw Error(`Authorization Server ${authorization_servers} did not provide a token_endpoint`); } else if (token_endpoint && authMetadata.token_endpoint !== token_endpoint) { throw Error(`Credential issuer has a different token_endpoint (${token_endpoint}) from the Authorization Server (${authMetadata.token_endpoint})`); } token_endpoint = authMetadata.token_endpoint; if (authMetadata.credential_endpoint) { if (credential_endpoint && authMetadata.credential_endpoint !== credential_endpoint) { debug(`Credential issuer has a different credential_endpoint (${credential_endpoint}) from the Authorization Server (${authMetadata.credential_endpoint}). Will use the issuer value`); } else { credential_endpoint = authMetadata.credential_endpoint; } } if (authMetadata.deferred_credential_endpoint) { if (deferred_credential_endpoint && authMetadata.deferred_credential_endpoint !== deferred_credential_endpoint) { debug(`Credential issuer has a different deferred_credential_endpoint (${deferred_credential_endpoint}) from the Authorization Server (${authMetadata.deferred_credential_endpoint}). Will use the issuer value`); } else { deferred_credential_endpoint = authMetadata.deferred_credential_endpoint; } } } if (!authorization_endpoint) { debug(`Issuer ${issuer} does not expose authorization_endpoint, so only pre-auth will be supported`); } if (!token_endpoint) { debug(`Issuer ${issuer} does not have a token_endpoint listed in well-known locations!`); if (opts === null || opts === void 0 ? void 0 : opts.errorOnNotFound) { throw Error(`Could not deduce the token_endpoint for ${issuer}`); } else { token_endpoint = `${issuer}${issuer.endsWith('/') ? 'token' : '/token'}`; } } if (!credential_endpoint) { debug(`Issuer ${issuer} does not have a credential_endpoint listed in well-known locations!`); if (opts === null || opts === void 0 ? void 0 : opts.errorOnNotFound) { throw Error(`Could not deduce the credential endpoint for ${issuer}`); } else { credential_endpoint = `${issuer}${issuer.endsWith('/') ? 'credential' : '/credential'}`; } } if (!credentialIssuerMetadata && authMetadata) { // Apparently everything worked out and the issuer is exposing everything in oAuth2/OIDC well-knowns. Spec is vague about this situation, but we can support it credentialIssuerMetadata = authMetadata; } debug(`Issuer ${issuer} token endpoint ${token_endpoint}, credential endpoint ${credential_endpoint}`); return { issuer, token_endpoint, credential_endpoint, deferred_credential_endpoint, authorization_server: authorization_servers[0], authorization_endpoint, authorization_challenge_endpoint, authorizationServerType, credentialIssuerMetadata: credentialIssuerMetadata, authorizationServerMetadata: authMetadata, }; }); } /** * Retrieve only the OID4VCI metadata for the issuer. So no OIDC/OAuth2 metadata * * @param issuerHost The issuer hostname * @param opts */ static retrieveOpenID4VCIServerMetadata(issuerHost, opts) { return __awaiter(this, void 0, void 0, function* () { return (0, functions_1.retrieveWellknown)(issuerHost, oid4vci_common_1.WellKnownEndpoints.OPENID4VCI_ISSUER, { errorOnNotFound: (opts === null || opts === void 0 ? void 0 : opts.errorOnNotFound) === undefined ? true : opts.errorOnNotFound, }); }); } } exports.MetadataClientV1_0_13 = MetadataClientV1_0_13; //# sourceMappingURL=MetadataClientV1_0_13.js.map