UNPKG

@sphereon/oid4vci-client

Version:

OpenID for Verifiable Credential Issuance (OpenID4VCI) client

179 lines • 10 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.CredentialRequestClientV1_0_11 = void 0; const oid4vc_common_1 = require("@sphereon/oid4vc-common"); const oid4vci_common_1 = require("@sphereon/oid4vci-common"); const debug_1 = __importDefault(require("debug")); const CredentialRequestClient_1 = require("./CredentialRequestClient"); const dpopUtil_1 = require("./functions/dpopUtil"); const debug = (0, debug_1.default)('sphereon:oid4vci:credential'); class CredentialRequestClientV1_0_11 { get credentialRequestOpts() { return this._credentialRequestOpts; } isDeferred() { return this._isDeferred; } getCredentialEndpoint() { return this.credentialRequestOpts.credentialEndpoint; } getDeferredCredentialEndpoint() { return this.credentialRequestOpts.deferredCredentialEndpoint; } constructor(builder) { this._isDeferred = false; this._credentialRequestOpts = Object.assign({}, builder); } acquireCredentialsUsingProof(opts) { return __awaiter(this, void 0, void 0, function* () { const { credentialTypes, proofInput, format, context } = opts; const request = yield this.createCredentialRequest({ proofInput, credentialTypes, context, format, version: this.version() }); return yield this.acquireCredentialsUsingRequest(request, opts.createDPoPOpts); }); } acquireCredentialsUsingRequest(uniformRequest, createDPoPOpts) { return __awaiter(this, void 0, void 0, function* () { const request = (0, oid4vci_common_1.getCredentialRequestForVersion)(uniformRequest, this.version()); const credentialEndpoint = this.credentialRequestOpts.credentialEndpoint; if (!(0, oid4vci_common_1.isValidURL)(credentialEndpoint)) { debug(`Invalid credential endpoint: ${credentialEndpoint}`); throw new Error(oid4vci_common_1.URL_NOT_VALID); } debug(`Acquiring credential(s) from: ${credentialEndpoint}`); debug(`request\n: ${JSON.stringify(request, null, 2)}`); const requestToken = this.credentialRequestOpts.token; let dPoP = createDPoPOpts ? yield (0, oid4vc_common_1.createDPoP)((0, oid4vc_common_1.getCreateDPoPOptions)(createDPoPOpts, credentialEndpoint, { accessToken: requestToken })) : undefined; let response = (yield (0, oid4vci_common_1.post)(credentialEndpoint, JSON.stringify(request), { bearerToken: requestToken, customHeaders: Object.assign({}, (createDPoPOpts && { dpop: dPoP })), })); let nextDPoPNonce = createDPoPOpts === null || createDPoPOpts === void 0 ? void 0 : createDPoPOpts.jwtPayloadProps.nonce; const retryWithNonce = (0, dpopUtil_1.shouldRetryResourceRequestWithDPoPNonce)(response); if (retryWithNonce.ok && createDPoPOpts) { createDPoPOpts.jwtPayloadProps.nonce = retryWithNonce.dpopNonce; dPoP = yield (0, oid4vc_common_1.createDPoP)((0, oid4vc_common_1.getCreateDPoPOptions)(createDPoPOpts, credentialEndpoint, { accessToken: requestToken })); response = (yield (0, oid4vci_common_1.post)(credentialEndpoint, JSON.stringify(request), { bearerToken: requestToken, customHeaders: Object.assign({}, (createDPoPOpts && { dpop: dPoP })), })); const successDPoPNonce = response.origResponse.headers.get('DPoP-Nonce'); nextDPoPNonce = successDPoPNonce !== null && successDPoPNonce !== void 0 ? successDPoPNonce : retryWithNonce.dpopNonce; } this._isDeferred = (0, oid4vci_common_1.isDeferredCredentialResponse)(response); if (this.isDeferred() && this.credentialRequestOpts.deferredCredentialAwait && response.successBody) { response = yield this.acquireDeferredCredential(response.successBody, { bearerToken: this.credentialRequestOpts.token }); } response.access_token = requestToken; debug(`Credential endpoint ${credentialEndpoint} response:\r\n${JSON.stringify(response, null, 2)}`); return Object.assign(Object.assign({}, response), (nextDPoPNonce && { params: { dpop: { dpopNonce: nextDPoPNonce } } })); }); } acquireDeferredCredential(response, opts) { return __awaiter(this, void 0, void 0, function* () { var _a; const transactionId = response.transaction_id; const bearerToken = (_a = response.acceptance_token) !== null && _a !== void 0 ? _a : opts === null || opts === void 0 ? void 0 : opts.bearerToken; const deferredCredentialEndpoint = this.getDeferredCredentialEndpoint(); if (!deferredCredentialEndpoint) { throw Error(`No deferred credential endpoint supplied.`); } else if (!bearerToken) { throw Error(`No bearer token present and refresh for defered endpoint not supported yet`); // todo updated bearer token with new c_nonce } return yield (0, oid4vci_common_1.acquireDeferredCredential)({ bearerToken, transactionId, deferredCredentialEndpoint, deferredCredentialAwait: this.credentialRequestOpts.deferredCredentialAwait, deferredCredentialIntervalInMS: this.credentialRequestOpts.deferredCredentialIntervalInMS, }); }); } createCredentialRequest(opts) { return __awaiter(this, void 0, void 0, function* () { var _a; const { proofInput } = opts; const formatSelection = (_a = opts.format) !== null && _a !== void 0 ? _a : this.credentialRequestOpts.format; if (!formatSelection) { throw Error(`Format of credential to be issued is missing`); } const format = (0, oid4vci_common_1.getUniformFormat)(formatSelection); const typesSelection = (opts === null || opts === void 0 ? void 0 : opts.credentialTypes) && (typeof opts.credentialTypes === 'string' || opts.credentialTypes.length > 0) ? opts.credentialTypes : this.credentialRequestOpts.credentialTypes; const types = Array.isArray(typesSelection) ? typesSelection : [typesSelection]; if (types.length === 0) { throw Error(`Credential type(s) need to be provided`); } // FIXME: this is mixing up the type (as id) from v8/v9 and the types (from the vc.type) from v11 else if (!this.isV11OrHigher() && types.length !== 1) { throw Error('Only a single credential type is supported for V8/V9'); } const proof = yield (0, CredentialRequestClient_1.buildProof)(proofInput, opts); // TODO: we should move format specific logic if (format === 'jwt_vc_json' || format === 'jwt_vc') { return { types, format, proof, }; } else if (format === 'jwt_vc_json-ld' || format === 'ldp_vc') { if (this.version() >= oid4vci_common_1.OpenId4VCIVersion.VER_1_0_12 && !opts.context) { throw Error('No @context value present, but it is required'); } return { format, proof, // Ignored because v11 does not have the context value, but it is required in v12 // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore credential_definition: Object.assign({ types }, (opts.context && { '@context': opts.context })), }; } else if (format === 'vc+sd-jwt') { if (types.length > 1) { throw Error(`Only a single credential type is supported for ${format}`); } return { format, proof, vct: types[0], }; } else if (format === 'mso_mdoc') { if (types.length > 1) { throw Error(`Only a single credential type is supported for ${format}`); } return { format, proof, doctype: types[0], }; } throw new Error(`Unsupported format: ${format}`); }); } version() { var _a, _b; return (_b = (_a = this.credentialRequestOpts) === null || _a === void 0 ? void 0 : _a.version) !== null && _b !== void 0 ? _b : oid4vci_common_1.OpenId4VCIVersion.VER_1_0_11; } isV11OrHigher() { return this.version() >= oid4vci_common_1.OpenId4VCIVersion.VER_1_0_11; } } exports.CredentialRequestClientV1_0_11 = CredentialRequestClientV1_0_11; //# sourceMappingURL=CredentialRequestClientV1_0_11.js.map