@sphereon/oid4vci-client
Version:
OpenID for Verifiable Credential Issuance (OpenID4VCI) client
134 lines • 8.54 kB
JavaScript
;
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