UNPKG

@sphereon/oid4vci-client

Version:

OpenID for Verifiable Credential Issuance (OpenID4VCI) client

134 lines • 8.54 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.createAuthorizationRequestUrlV1_0_11 = void 0; const oid4vci_common_1 = require("@sphereon/oid4vci-common"); const debug_1 = __importDefault(require("debug")); const AuthorizationCodeClient_1 = require("./AuthorizationCodeClient"); const debug = (0, debug_1.default)('sphereon:oid4vci'); const createAuthorizationRequestUrlV1_0_11 = (_a) => __awaiter(void 0, [_a], void 0, function* ({ pkce, endpointMetadata, authorizationRequest, credentialOffer, credentialsSupported, }) { var _b, _c, _d, _e; const { redirectUri, clientId, requestObjectOpts = { requestObjectMode: oid4vci_common_1.CreateRequestObjectMode.NONE } } = authorizationRequest; let { scope, authorizationDetails } = authorizationRequest; const parMode = ((_b = endpointMetadata === null || endpointMetadata === void 0 ? void 0 : endpointMetadata.credentialIssuerMetadata) === null || _b === void 0 ? void 0 : _b.require_pushed_authorization_requests) ? oid4vci_common_1.PARMode.REQUIRE : ((_c = authorizationRequest.parMode) !== null && _c !== void 0 ? _c : oid4vci_common_1.PARMode.AUTO); // Scope and authorization_details can be used in the same authorization request // https://datatracker.ietf.org/doc/html/draft-ietf-oauth-rar-23#name-relationship-to-scope-param if (!scope && !authorizationDetails) { if (!credentialOffer) { throw Error('Please provide a scope or authorization_details if no credential offer is present'); } const creds = credentialOffer.credential_offer.credentials; // FIXME: complains about VCT for sd-jwt // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore authorizationDetails = creds .flatMap((cred) => (typeof cred === 'string' ? credentialsSupported : cred)) .filter((cred) => !!cred) .map((cred) => { return Object.assign(Object.assign({}, cred), { type: 'openid_credential', locations: [endpointMetadata.issuer], // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore format: cred.format }); }); if (!authorizationDetails || (Array.isArray(authorizationDetails) && authorizationDetails.length === 0)) { throw Error(`Could not create authorization details from credential offer. Please pass in explicit details`); } } if (!(endpointMetadata === null || endpointMetadata === void 0 ? void 0 : endpointMetadata.authorization_endpoint)) { throw Error('Server metadata does not contain authorization endpoint'); } const parEndpoint = (_d = endpointMetadata.credentialIssuerMetadata) === null || _d === void 0 ? void 0 : _d.pushed_authorization_request_endpoint; // add 'openid' scope if not present if (!(scope === null || scope === void 0 ? void 0 : scope.includes('openid'))) { scope = ['openid', scope].filter((s) => !!s).join(' '); } let queryObj = Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({ response_type: oid4vci_common_1.ResponseType.AUTH_CODE }, (!pkce.disabled && { code_challenge_method: (_e = pkce.codeChallengeMethod) !== null && _e !== void 0 ? _e : oid4vci_common_1.CodeChallengeMethod.S256, code_challenge: pkce.codeChallenge, })), { authorization_details: JSON.stringify(handleAuthorizationDetailsV1_0_11(endpointMetadata, authorizationDetails)) }), (redirectUri && { redirect_uri: redirectUri })), (clientId && { client_id: clientId })), ((credentialOffer === null || credentialOffer === void 0 ? void 0 : credentialOffer.issuerState) && { issuer_state: credentialOffer.issuerState })), { scope }); if (!parEndpoint && parMode === oid4vci_common_1.PARMode.REQUIRE) { throw Error(`PAR mode is set to required by Authorization Server does not support PAR!`); } else if (parEndpoint && parMode !== oid4vci_common_1.PARMode.NEVER) { debug(`USING PAR with endpoint ${parEndpoint}`); const parResponse = yield (0, oid4vci_common_1.formPost)(parEndpoint, (0, oid4vci_common_1.convertJsonToURI)(queryObj, { mode: oid4vci_common_1.JsonURIMode.X_FORM_WWW_URLENCODED, uriTypeProperties: ['client_id', 'request_uri', 'redirect_uri', 'scope', 'authorization_details', 'issuer_state'], }), { contentType: 'application/x-www-form-urlencoded', accept: 'application/json' }); if (parResponse.errorBody || !parResponse.successBody) { console.log(JSON.stringify(parResponse.errorBody)); console.log('Falling back to regular request URI, since PAR failed'); if (parMode === oid4vci_common_1.PARMode.REQUIRE) { throw Error(`PAR error: ${parResponse.origResponse.statusText}`); } } else { debug(`PAR response: ${JSON.stringify(parResponse.successBody, null, 2)}`); queryObj = { request_uri: parResponse.successBody.request_uri }; } } yield (0, AuthorizationCodeClient_1.createSignedAuthRequestWhenNeeded)(queryObj, Object.assign(Object.assign({}, requestObjectOpts), { aud: endpointMetadata.authorization_server })); debug(`Object that will become query params: ` + JSON.stringify(queryObj, null, 2)); const url = (0, oid4vci_common_1.convertJsonToURI)(queryObj, { baseUrl: endpointMetadata.authorization_endpoint, uriTypeProperties: ['client_id', 'request_uri', 'redirect_uri', 'scope', 'authorization_details', 'issuer_state'], // arrayTypeProperties: ['authorization_details'], mode: oid4vci_common_1.JsonURIMode.X_FORM_WWW_URLENCODED, // We do not add the version here, as this always needs to be form encoded }); debug(`Authorization Request URL: ${url}`); return url; }); exports.createAuthorizationRequestUrlV1_0_11 = createAuthorizationRequestUrlV1_0_11; const handleAuthorizationDetailsV1_0_11 = (endpointMetadata, authorizationDetails) => { if (authorizationDetails) { if (typeof authorizationDetails === 'string') { // backwards compat for older versions of the lib return authorizationDetails; } if (Array.isArray(authorizationDetails)) { return authorizationDetails .filter((value) => typeof value !== 'string') .map((value) => handleLocations(endpointMetadata, typeof value === 'string' ? value : Object.assign({}, value))); } else { return handleLocations(endpointMetadata, Object.assign({}, authorizationDetails)); } } return authorizationDetails; }; const handleLocations = (endpointMetadata, authorizationDetails) => { var _a; if (typeof authorizationDetails === 'string') { // backwards compat for older versions of the lib return authorizationDetails; } if (authorizationDetails && (((_a = endpointMetadata.credentialIssuerMetadata) === null || _a === void 0 ? void 0 : _a.authorization_server) || endpointMetadata.authorization_endpoint)) { if (authorizationDetails.locations) { if (Array.isArray(authorizationDetails.locations)) { authorizationDetails.locations.push(endpointMetadata.issuer); } else { authorizationDetails.locations = [authorizationDetails.locations, endpointMetadata.issuer]; } } else { authorizationDetails.locations = [endpointMetadata.issuer]; } } return authorizationDetails; }; //# sourceMappingURL=AuthorizationCodeClientV1_0_11.js.map