@sphereon/oid4vci-client
Version:
OpenID for Verifiable Credential Issuance (OpenID4VCI) client
565 lines • 35.3 kB
JavaScript
"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.OpenID4VCIClient = void 0;
const oid4vci_common_1 = require("@sphereon/oid4vci-common");
const debug_1 = __importDefault(require("debug"));
const AccessTokenClient_1 = require("./AccessTokenClient");
const AccessTokenClientV1_0_11_1 = require("./AccessTokenClientV1_0_11");
const AuthorizationCodeClient_1 = require("./AuthorizationCodeClient");
const AuthorizationCodeClientV1_0_11_1 = require("./AuthorizationCodeClientV1_0_11");
const CredentialOfferClient_1 = require("./CredentialOfferClient");
const CredentialRequestClientBuilderV1_0_11_1 = require("./CredentialRequestClientBuilderV1_0_11");
const CredentialRequestClientBuilderV1_0_13_1 = require("./CredentialRequestClientBuilderV1_0_13");
const MetadataClient_1 = require("./MetadataClient");
const ProofOfPossessionBuilder_1 = require("./ProofOfPossessionBuilder");
const functions_1 = require("./functions");
const debug = (0, debug_1.default)('sphereon:oid4vci');
class OpenID4VCIClient {
constructor({ credentialOffer, clientId, kid, alg, credentialIssuer, pkce, authorizationRequest, accessToken, jwk, endpointMetadata, accessTokenResponse, authorizationRequestOpts, authorizationCodeResponse, authorizationURL, }) {
var _a, _b;
this.getAuthorizationCode = (authorizationResponse, code) => {
var _a, _b, _c;
if (authorizationResponse) {
this._state.authorizationCodeResponse = Object.assign({}, (0, oid4vci_common_1.toAuthorizationResponsePayload)(authorizationResponse));
}
else if (code) {
this._state.authorizationCodeResponse = { code };
}
return ((_b = (_a = this._state.authorizationCodeResponse) === null || _a === void 0 ? void 0 : _a.code) !== null && _b !== void 0 ? _b : (_c = this._state.authorizationCodeResponse) === null || _c === void 0 ? void 0 : _c.authorization_code);
};
const issuer = credentialIssuer !== null && credentialIssuer !== void 0 ? credentialIssuer : (credentialOffer ? (0, oid4vci_common_1.getIssuerFromCredentialOfferPayload)(credentialOffer.credential_offer) : undefined);
if (!issuer) {
throw Error('No credential issuer supplied or deduced from offer');
}
this._state = {
credentialOffer,
credentialIssuer: issuer,
kid,
alg,
// TODO: We need to refactor this and always explicitly call createAuthorizationRequestUrl, so we can have a credential selection first and use the kid as a default for the client id
clientId: (_a = clientId !== null && clientId !== void 0 ? clientId : (credentialOffer && (0, oid4vci_common_1.getClientIdFromCredentialOfferPayload)(credentialOffer.credential_offer))) !== null && _a !== void 0 ? _a : kid === null || kid === void 0 ? void 0 : kid.split('#')[0],
pkce: Object.assign({ disabled: false, codeChallengeMethod: oid4vci_common_1.CodeChallengeMethod.S256 }, pkce),
authorizationRequestOpts,
authorizationCodeResponse,
accessToken,
jwk,
endpointMetadata: ((_b = endpointMetadata === null || endpointMetadata === void 0 ? void 0 : endpointMetadata.credentialIssuerMetadata) === null || _b === void 0 ? void 0 : _b.authorization_server)
? endpointMetadata
: endpointMetadata,
accessTokenResponse,
authorizationURL,
};
// Running syncAuthorizationRequestOpts later as it is using the state
if (!this._state.authorizationRequestOpts) {
this._state.authorizationRequestOpts = this.syncAuthorizationRequestOpts(authorizationRequest);
}
debug(`Authorization req options: ${JSON.stringify(this._state.authorizationRequestOpts, null, 2)}`);
}
static fromCredentialIssuer(_a) {
return __awaiter(this, arguments, void 0, function* ({ kid, alg, retrieveServerMetadata, clientId, credentialIssuer, pkce, authorizationRequest, createAuthorizationRequestURL, endpointMetadata, }) {
const client = new OpenID4VCIClient({
kid,
alg,
clientId: clientId !== null && clientId !== void 0 ? clientId : authorizationRequest === null || authorizationRequest === void 0 ? void 0 : authorizationRequest.clientId,
credentialIssuer,
pkce,
authorizationRequest,
endpointMetadata,
});
if (retrieveServerMetadata === undefined || retrieveServerMetadata) {
yield client.retrieveServerMetadata();
}
if (createAuthorizationRequestURL === undefined || createAuthorizationRequestURL) {
yield client.createAuthorizationRequestUrl({ authorizationRequest, pkce });
}
return client;
});
}
static fromState(_a) {
return __awaiter(this, arguments, void 0, function* ({ state }) {
const clientState = typeof state === 'string' ? JSON.parse(state) : state;
return new OpenID4VCIClient(clientState);
});
}
static fromURI(_a) {
return __awaiter(this, arguments, void 0, function* ({ uri, kid, alg, retrieveServerMetadata, clientId, pkce, createAuthorizationRequestURL, authorizationRequest, resolveOfferUri, endpointMetadata, }) {
var _b;
const credentialOfferClient = yield CredentialOfferClient_1.CredentialOfferClient.fromURI(uri, { resolve: resolveOfferUri });
const client = new OpenID4VCIClient({
credentialOffer: credentialOfferClient,
kid,
alg,
clientId: (_b = clientId !== null && clientId !== void 0 ? clientId : authorizationRequest === null || authorizationRequest === void 0 ? void 0 : authorizationRequest.clientId) !== null && _b !== void 0 ? _b : credentialOfferClient.clientId,
pkce,
authorizationRequest,
endpointMetadata,
});
if (retrieveServerMetadata === undefined || retrieveServerMetadata) {
yield client.retrieveServerMetadata();
}
if (credentialOfferClient.supportedFlows.includes(oid4vci_common_1.AuthzFlowType.AUTHORIZATION_CODE_FLOW) &&
(createAuthorizationRequestURL === undefined || createAuthorizationRequestURL)) {
yield client.createAuthorizationRequestUrl({ authorizationRequest, pkce });
debug(`Authorization Request URL: ${client._state.authorizationURL}`);
}
return client;
});
}
/**
* Allows you to create an Authorization Request URL when using an Authorization Code flow. This URL needs to be accessed using the front channel (browser)
*
* The Identity provider would present a login screen typically; after you authenticated, it would redirect to the provided redirectUri; which can be same device or cross-device
* @param opts
*/
createAuthorizationRequestUrl(opts) {
return __awaiter(this, void 0, void 0, function* () {
var _a;
if (!this._state.authorizationURL) {
this.calculatePKCEOpts(opts === null || opts === void 0 ? void 0 : opts.pkce);
this._state.authorizationRequestOpts = this.syncAuthorizationRequestOpts(opts === null || opts === void 0 ? void 0 : opts.authorizationRequest);
if (!this._state.authorizationRequestOpts) {
throw Error(`No Authorization Request options present or provided in this call`);
}
// todo: Probably can go with current logic in MetadataClient who will always set the authorization_endpoint when found
// handling this because of the support for v1_0-08
if (((_a = this._state.endpointMetadata) === null || _a === void 0 ? void 0 : _a.credentialIssuerMetadata) &&
'authorization_endpoint' in this._state.endpointMetadata.credentialIssuerMetadata) {
this._state.endpointMetadata.authorization_endpoint = this._state.endpointMetadata.credentialIssuerMetadata.authorization_endpoint;
}
if (this.version() <= oid4vci_common_1.OpenId4VCIVersion.VER_1_0_11) {
this._state.authorizationURL = yield (0, AuthorizationCodeClientV1_0_11_1.createAuthorizationRequestUrlV1_0_11)({
pkce: this._state.pkce,
endpointMetadata: this.endpointMetadata,
authorizationRequest: this._state.authorizationRequestOpts,
credentialOffer: this.credentialOffer,
credentialsSupported: Object.values(this.getCredentialsSupported(true)),
});
}
else {
this._state.authorizationURL = yield (0, AuthorizationCodeClient_1.createAuthorizationRequestUrl)({
pkce: this._state.pkce,
endpointMetadata: this.endpointMetadata,
authorizationRequest: this._state.authorizationRequestOpts,
credentialOffer: this.credentialOffer,
credentialConfigurationSupported: this.getCredentialsSupported(false),
});
}
}
return this._state.authorizationURL;
});
}
retrieveServerMetadata() {
return __awaiter(this, void 0, void 0, function* () {
this.assertIssuerData();
if (!this._state.endpointMetadata) {
if (this.credentialOffer) {
this._state.endpointMetadata = yield MetadataClient_1.MetadataClient.retrieveAllMetadataFromCredentialOffer(this.credentialOffer);
}
else if (this._state.credentialIssuer) {
this._state.endpointMetadata = yield MetadataClient_1.MetadataClient.retrieveAllMetadata(this._state.credentialIssuer);
}
else {
throw Error(`Cannot retrieve issuer metadata without either a credential offer, or issuer value`);
}
}
return this.endpointMetadata;
});
}
calculatePKCEOpts(pkce) {
this._state.pkce = (0, functions_1.generateMissingPKCEOpts)(Object.assign(Object.assign({}, this._state.pkce), pkce));
}
acquireAuthorizationChallengeCode(opts) {
return __awaiter(this, void 0, void 0, function* () {
var _a, _b, _c;
const response = yield (0, AuthorizationCodeClient_1.acquireAuthorizationChallengeAuthCode)(Object.assign({ metadata: this.endpointMetadata, credentialIssuer: this.getIssuer(), clientId: (_a = this._state.clientId) !== null && _a !== void 0 ? _a : (_b = this._state.authorizationRequestOpts) === null || _b === void 0 ? void 0 : _b.clientId }, opts));
if (response.errorBody) {
debug(`Authorization code error:\r\n${JSON.stringify(response.errorBody)}`);
const error = response.errorBody;
return Promise.reject(error);
}
else if (!response.successBody) {
debug(`Authorization code error. No success body`);
return Promise.reject(Error(`Retrieving an authorization code token from ${(_c = this._state.endpointMetadata) === null || _c === void 0 ? void 0 : _c.authorization_challenge_endpoint} for issuer ${this.getIssuer()} failed as there was no success response body`));
}
return Object.assign({}, response.successBody);
});
}
acquireAccessToken(opts) {
return __awaiter(this, void 0, void 0, function* () {
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v;
const { pin, clientId = (_a = this._state.clientId) !== null && _a !== void 0 ? _a : (_b = this._state.authorizationRequestOpts) === null || _b === void 0 ? void 0 : _b.clientId } = opts !== null && opts !== void 0 ? opts : {};
let { redirectUri } = opts !== null && opts !== void 0 ? opts : {};
const code = this.getAuthorizationCode(opts === null || opts === void 0 ? void 0 : opts.authorizationResponse, opts === null || opts === void 0 ? void 0 : opts.code);
if (opts === null || opts === void 0 ? void 0 : opts.codeVerifier) {
this._state.pkce.codeVerifier = opts.codeVerifier;
}
this.assertIssuerData();
const asOpts = Object.assign({}, opts === null || opts === void 0 ? void 0 : opts.asOpts);
const kid = (_e = (_d = (_c = asOpts.clientOpts) === null || _c === void 0 ? void 0 : _c.kid) !== null && _d !== void 0 ? _d : this._state.kid) !== null && _e !== void 0 ? _e : (_g = (_f = this._state.authorizationRequestOpts) === null || _f === void 0 ? void 0 : _f.requestObjectOpts) === null || _g === void 0 ? void 0 : _g.kid;
const clientAssertionType = (_j = (_h = asOpts.clientOpts) === null || _h === void 0 ? void 0 : _h.clientAssertionType) !== null && _j !== void 0 ? _j : (kid && clientId && typeof ((_l = (_k = asOpts.clientOpts) === null || _k === void 0 ? void 0 : _k.signCallbacks) === null || _l === void 0 ? void 0 : _l.signCallback) === 'function'
? 'urn:ietf:params:oauth:client-assertion-type:jwt-bearer'
: undefined);
if (this.isEBSI() || (clientId && kid)) {
if (!clientId) {
throw Error(`Client id expected for EBSI`);
}
asOpts.clientOpts = Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({}, asOpts.clientOpts), { clientId }), (kid && { kid })), (clientAssertionType && { clientAssertionType })), { signCallbacks: (_o = (_m = asOpts.clientOpts) === null || _m === void 0 ? void 0 : _m.signCallbacks) !== null && _o !== void 0 ? _o : (_q = (_p = this._state.authorizationRequestOpts) === null || _p === void 0 ? void 0 : _p.requestObjectOpts) === null || _q === void 0 ? void 0 : _q.signCallbacks });
}
if (clientId) {
this._state.clientId = clientId;
if (!asOpts.clientOpts) {
asOpts.clientOpts = { clientId };
}
asOpts.clientOpts.clientId = clientId;
}
if (!this._state.accessTokenResponse) {
const accessTokenClient = this.version() <= oid4vci_common_1.OpenId4VCIVersion.VER_1_0_12 ? new AccessTokenClientV1_0_11_1.AccessTokenClientV1_0_11() : new AccessTokenClient_1.AccessTokenClient();
if (redirectUri && redirectUri !== ((_r = this._state.authorizationRequestOpts) === null || _r === void 0 ? void 0 : _r.redirectUri)) {
console.log(`Redirect URI mismatch between access-token (${redirectUri}) and authorization request (${(_s = this._state.authorizationRequestOpts) === null || _s === void 0 ? void 0 : _s.redirectUri}). According to the specification that is not allowed.`);
}
if (((_t = this._state.authorizationRequestOpts) === null || _t === void 0 ? void 0 : _t.redirectUri) && !redirectUri) {
redirectUri = this._state.authorizationRequestOpts.redirectUri;
}
const response = yield accessTokenClient.acquireAccessToken(Object.assign(Object.assign(Object.assign(Object.assign({ credentialOffer: this.credentialOffer, metadata: this.endpointMetadata, credentialIssuer: this.getIssuer(), pin }, (!this._state.pkce.disabled && { codeVerifier: this._state.pkce.codeVerifier })), { code,
redirectUri,
asOpts }), ((opts === null || opts === void 0 ? void 0 : opts.createDPoPOpts) && { createDPoPOpts: opts.createDPoPOpts })), ((opts === null || opts === void 0 ? void 0 : opts.additionalRequestParams) && { additionalParams: opts.additionalRequestParams })));
if (response.errorBody) {
debug(`Access token error:\r\n${JSON.stringify(response.errorBody)}`);
throw Error(`Retrieving an access token from ${(_u = this._state.endpointMetadata) === null || _u === void 0 ? void 0 : _u.token_endpoint} for issuer ${this.getIssuer()} failed with status: ${response.origResponse.status}`);
}
else if (!response.successBody) {
debug(`Access token error. No success body`);
throw Error(`Retrieving an access token from ${(_v = this._state.endpointMetadata) === null || _v === void 0 ? void 0 : _v.token_endpoint} for issuer ${this.getIssuer()} failed as there was no success response body`);
}
this._state.accessTokenResponse = response.successBody;
this._state.dpopResponseParams = response.params;
this._state.accessToken = response.successBody.access_token;
}
return Object.assign(Object.assign({}, this.accessTokenResponse), (this.dpopResponseParams && { params: this.dpopResponseParams }));
});
}
acquireCredentials(_a) {
return __awaiter(this, arguments, void 0, function* ({ credentialTypes, context, proofCallbacks, format, kid, jwk, alg, jti, deferredCredentialAwait, deferredCredentialIntervalInMS, createDPoPOpts, }) {
var _b, _c, _d, _e, _f;
if ([jwk, kid].filter((v) => v !== undefined).length > 1) {
throw new Error(oid4vci_common_1.KID_JWK_X5C_ERROR + `. jwk: ${jwk !== undefined}, kid: ${kid !== undefined}`);
}
if (alg)
this._state.alg = alg;
if (jwk)
this._state.jwk = jwk;
if (kid)
this._state.kid = kid;
let requestBuilder;
if (this.version() < oid4vci_common_1.OpenId4VCIVersion.VER_1_0_13) {
requestBuilder = this.credentialOffer
? CredentialRequestClientBuilderV1_0_11_1.CredentialRequestClientBuilderV1_0_11.fromCredentialOffer({
credentialOffer: this.credentialOffer,
metadata: this.endpointMetadata,
})
: CredentialRequestClientBuilderV1_0_11_1.CredentialRequestClientBuilderV1_0_11.fromCredentialIssuer({
credentialIssuer: this.getIssuer(),
credentialTypes,
metadata: this.endpointMetadata,
version: this.version(),
});
}
else {
requestBuilder = this.credentialOffer
? CredentialRequestClientBuilderV1_0_13_1.CredentialRequestClientBuilderV1_0_13.fromCredentialOffer({
credentialOffer: this.credentialOffer,
metadata: this.endpointMetadata,
})
: CredentialRequestClientBuilderV1_0_13_1.CredentialRequestClientBuilderV1_0_13.fromCredentialIssuer({
credentialIssuer: this.getIssuer(),
credentialTypes,
metadata: this.endpointMetadata,
version: this.version(),
});
}
// If we are in an auth code flow, without a c nonce, we return the issuerState back to the issuer in case it is present
const issuerState = this.issuerSupportedFlowTypes().includes(oid4vci_common_1.AuthzFlowType.AUTHORIZATION_CODE_FLOW) &&
this._state.authorizationCodeResponse &&
!((_b = this.accessTokenResponse) === null || _b === void 0 ? void 0 : _b.c_nonce) &&
((_c = this._state.credentialOffer) === null || _c === void 0 ? void 0 : _c.issuerState)
? this._state.credentialOffer.issuerState
: undefined;
requestBuilder.withIssuerState(issuerState);
requestBuilder.withTokenFromResponse(this.accessTokenResponse);
requestBuilder.withDeferredCredentialAwait(deferredCredentialAwait !== null && deferredCredentialAwait !== void 0 ? deferredCredentialAwait : false, deferredCredentialIntervalInMS);
let subjectIssuance;
if ((_d = this.endpointMetadata) === null || _d === void 0 ? void 0 : _d.credentialIssuerMetadata) {
const metadata = this.endpointMetadata.credentialIssuerMetadata;
const types = Array.isArray(credentialTypes) ? credentialTypes : [credentialTypes];
if (metadata.credentials_supported && Array.isArray(metadata.credentials_supported)) {
let typeSupported = false;
metadata.credentials_supported.forEach((supportedCredential) => {
const subTypes = (0, oid4vci_common_1.getTypesFromCredentialSupported)(supportedCredential);
if (subTypes.every((t, i) => types[i] === t) ||
(types.length === 1 && (types[0] === supportedCredential.id || subTypes.includes(types[0])))) {
typeSupported = true;
if (supportedCredential.credential_subject_issuance) {
subjectIssuance = { credential_subject_issuance: supportedCredential.credential_subject_issuance };
}
}
});
if (!typeSupported) {
console.log(`Not all credential types ${JSON.stringify(credentialTypes)} are present in metadata for ${this.getIssuer()}`);
// throw Error(`Not all credential types ${JSON.stringify(credentialTypes)} are supported by issuer ${this.getIssuer()}`);
}
}
else if (metadata.credentials_supported && !Array.isArray(metadata.credentials_supported)) {
const credentialsSupported = metadata.credentials_supported;
if (types.some((type) => !metadata.credentials_supported || !credentialsSupported[type])) {
throw Error(`Not all credential types ${JSON.stringify(credentialTypes)} are supported by issuer ${this.getIssuer()}`);
}
}
// todo: Format check? We might end up with some disjoint type / format combinations supported by the server
}
if (subjectIssuance) {
requestBuilder.withSubjectIssuance(subjectIssuance);
}
const credentialRequestClient = requestBuilder.build();
const proofBuilder = ProofOfPossessionBuilder_1.ProofOfPossessionBuilder.fromAccessTokenResponse({
accessTokenResponse: this.accessTokenResponse,
callbacks: proofCallbacks,
version: this.version(),
})
.withIssuer(this.getIssuer())
.withAlg(this.alg);
if (this._state.jwk) {
proofBuilder.withJWK(this._state.jwk);
}
if (this._state.kid) {
proofBuilder.withKid(this._state.kid);
}
if (this.clientId) {
proofBuilder.withClientId(this.clientId);
}
if (jti) {
proofBuilder.withJti(jti);
}
const response = yield credentialRequestClient.acquireCredentialsUsingProof({
proofInput: proofBuilder,
credentialTypes,
context,
format,
subjectIssuance,
createDPoPOpts,
});
this._state.dpopResponseParams = response.params;
if (response.errorBody) {
debug(`Credential request error:\r\n${JSON.stringify(response.errorBody)}`);
throw Error(`Retrieving a credential from ${(_e = this._state.endpointMetadata) === null || _e === void 0 ? void 0 : _e.credential_endpoint} for issuer ${this.getIssuer()} failed with status: ${response.origResponse.status}`);
}
else if (!response.successBody) {
debug(`Credential request error. No success body`);
throw Error(`Retrieving a credential from ${(_f = this._state.endpointMetadata) === null || _f === void 0 ? void 0 : _f.credential_endpoint} for issuer ${this.getIssuer()} failed as there was no success response body`);
}
return Object.assign(Object.assign(Object.assign({}, response.successBody), (this.dpopResponseParams && { params: this.dpopResponseParams })), { access_token: response.access_token });
});
}
exportState() {
return __awaiter(this, void 0, void 0, function* () {
return JSON.stringify(this._state);
});
}
getCredentialsSupported(restrictToInitiationTypes, format) {
return (0, oid4vci_common_1.getSupportedCredentials)({
issuerMetadata: this.endpointMetadata.credentialIssuerMetadata,
version: this.version(),
format: format,
types: restrictToInitiationTypes ? this.getCredentialOfferTypes() : undefined,
});
}
sendNotification(credentialRequestOpts, request, accessToken) {
return __awaiter(this, void 0, void 0, function* () {
var _a, _b;
return (0, functions_1.sendNotification)(credentialRequestOpts, request, (_a = accessToken !== null && accessToken !== void 0 ? accessToken : this._state.accessToken) !== null && _a !== void 0 ? _a : (_b = this._state.accessTokenResponse) === null || _b === void 0 ? void 0 : _b.access_token);
});
}
getCredentialOfferTypes() {
if (!this.credentialOffer) {
return [];
}
else if (this.version() < oid4vci_common_1.OpenId4VCIVersion.VER_1_0_11) {
const orig = this.credentialOffer.original_credential_offer;
const types = typeof orig.credential_type === 'string' ? [orig.credential_type] : orig.credential_type;
const result = [];
result[0] = types;
return result;
}
else if (this.version() < oid4vci_common_1.OpenId4VCIVersion.VER_1_0_13) {
return this.credentialOffer.credential_offer.credentials.map((c) => { var _a; return (_a = (0, oid4vci_common_1.getTypesFromObject)(c)) !== null && _a !== void 0 ? _a : []; });
}
// we don't have this for v13. v13 only has credential_configuration_ids which is not translatable to type
return undefined;
}
issuerSupportedFlowTypes() {
var _a, _b, _c, _d, _e, _f;
return ((_b = (_a = this.credentialOffer) === null || _a === void 0 ? void 0 : _a.supportedFlows) !== null && _b !== void 0 ? _b : (((_e = (_d = (_c = this._state.endpointMetadata) === null || _c === void 0 ? void 0 : _c.credentialIssuerMetadata) === null || _d === void 0 ? void 0 : _d.authorization_endpoint) !== null && _e !== void 0 ? _e : (_f = this._state.endpointMetadata) === null || _f === void 0 ? void 0 : _f.authorization_server)
? [oid4vci_common_1.AuthzFlowType.AUTHORIZATION_CODE_FLOW]
: []));
}
isFlowTypeSupported(flowType) {
return this.issuerSupportedFlowTypes().includes(flowType);
}
get authorizationURL() {
return this._state.authorizationURL;
}
hasAuthorizationURL() {
return !!this.authorizationURL;
}
get credentialOffer() {
return this._state.credentialOffer;
}
version() {
var _a;
if (((_a = this.credentialOffer) === null || _a === void 0 ? void 0 : _a.version) && this.credentialOffer.version !== oid4vci_common_1.OpenId4VCIVersion.VER_UNKNOWN) {
return this.credentialOffer.version;
}
const metadata = this._state.endpointMetadata;
if (metadata === null || metadata === void 0 ? void 0 : metadata.credentialIssuerMetadata) {
const versions = (0, oid4vci_common_1.determineVersionsFromIssuerMetadata)(metadata.credentialIssuerMetadata);
if (versions.length > 0 && !versions.includes(oid4vci_common_1.OpenId4VCIVersion.VER_UNKNOWN)) {
return versions[0];
}
}
return oid4vci_common_1.OpenId4VCIVersion.VER_1_0_13;
}
get endpointMetadata() {
this.assertServerMetadata();
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
return this._state.endpointMetadata;
}
get kid() {
this.assertIssuerData();
if (!this._state.kid) {
throw new Error('No value for kid is supplied');
}
return this._state.kid;
}
get alg() {
this.assertIssuerData();
if (!this._state.alg) {
throw new Error('No value for alg is supplied');
}
return this._state.alg;
}
set clientId(value) {
this._state.clientId = value;
}
get clientId() {
return this._state.clientId;
}
hasAccessTokenResponse() {
return !!this._state.accessTokenResponse;
}
get accessTokenResponse() {
this.assertAccessToken();
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
return this._state.accessTokenResponse;
}
get dpopResponseParams() {
return this._state.dpopResponseParams;
}
getIssuer() {
this.assertIssuerData();
return this._state.credentialIssuer;
}
getAccessTokenEndpoint() {
this.assertIssuerData();
if (this.endpointMetadata) {
return this.endpointMetadata.token_endpoint;
}
return this.version() <= oid4vci_common_1.OpenId4VCIVersion.VER_1_0_12
? AccessTokenClientV1_0_11_1.AccessTokenClientV1_0_11.determineTokenURL({ issuerOpts: { issuer: this.getIssuer() } })
: AccessTokenClient_1.AccessTokenClient.determineTokenURL({ issuerOpts: { issuer: this.getIssuer() } });
}
getCredentialEndpoint() {
this.assertIssuerData();
return this.endpointMetadata ? this.endpointMetadata.credential_endpoint : `${this.getIssuer()}/credential`;
}
getAuthorizationChallengeEndpoint() {
var _a;
this.assertIssuerData();
return (_a = this.endpointMetadata) === null || _a === void 0 ? void 0 : _a.authorization_challenge_endpoint;
}
hasAuthorizationChallengeEndpoint() {
return !!this.getAuthorizationChallengeEndpoint();
}
hasDeferredCredentialEndpoint() {
return !!this.getAccessTokenEndpoint();
}
getDeferredCredentialEndpoint() {
this.assertIssuerData();
return this.endpointMetadata ? this.endpointMetadata.credential_endpoint : `${this.getIssuer()}/credential`;
}
/**
* Too bad we need a method like this, but EBSI is not exposing metadata
*/
isEBSI() {
var _a, _b, _c, _d, _e, _f, _g, _h, _j;
if (this.credentialOffer &&
((_c = (_b = (_a = this.credentialOffer) === null || _a === void 0 ? void 0 : _a.credential_offer) === null || _b === void 0 ? void 0 : _b.credentials) === null || _c === void 0 ? void 0 : _c.find((cred) =>
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
typeof cred !== 'string' && 'trust_framework' in cred && 'name' in cred.trust_framework && cred.trust_framework.name.includes('ebsi')))) {
return true;
}
// this.assertIssuerData();
return (((_d = this.clientId) === null || _d === void 0 ? void 0 : _d.includes('ebsi')) ||
((_e = this._state.kid) === null || _e === void 0 ? void 0 : _e.includes('did:ebsi:')) ||
this.getIssuer().includes('ebsi') ||
((_g = (_f = this.endpointMetadata.credentialIssuerMetadata) === null || _f === void 0 ? void 0 : _f.authorization_endpoint) === null || _g === void 0 ? void 0 : _g.includes('ebsi.eu')) ||
((_j = (_h = this.endpointMetadata.credentialIssuerMetadata) === null || _h === void 0 ? void 0 : _h.authorization_server) === null || _j === void 0 ? void 0 : _j.includes('ebsi.eu')));
}
assertIssuerData() {
if (!this._state.credentialIssuer) {
throw Error(`No credential issuer value present`);
}
else if (!this._state.credentialOffer && this._state.endpointMetadata && this.issuerSupportedFlowTypes().length === 0) {
throw Error(`No issuance initiation or credential offer present`);
}
}
assertServerMetadata() {
if (!this._state.endpointMetadata) {
throw Error('No server metadata');
}
}
assertAccessToken() {
if (!this._state.accessTokenResponse) {
throw Error(`No access token present`);
}
}
syncAuthorizationRequestOpts(opts) {
var _a, _b, _c, _d;
const requestObjectOpts = Object.assign(Object.assign({}, (_b = (_a = this._state) === null || _a === void 0 ? void 0 : _a.authorizationRequestOpts) === null || _b === void 0 ? void 0 : _b.requestObjectOpts), opts === null || opts === void 0 ? void 0 : opts.requestObjectOpts);
let authorizationRequestOpts = Object.assign(Object.assign(Object.assign({}, (_c = this._state) === null || _c === void 0 ? void 0 : _c.authorizationRequestOpts), opts), (requestObjectOpts && { requestObjectOpts }));
if (!authorizationRequestOpts) {
// We only set a redirectUri if no options are provided.
// Note that this only works for mobile apps, that can handle a code query param on the default openid-credential-offer deeplink.
// Provide your own options if that is not desired!
authorizationRequestOpts = { redirectUri: `${oid4vci_common_1.DefaultURISchemes.CREDENTIAL_OFFER}://` };
}
const clientId = (_d = authorizationRequestOpts.clientId) !== null && _d !== void 0 ? _d : this._state.clientId;
// sync clientId
this._state.clientId = clientId;
authorizationRequestOpts.clientId = clientId;
return authorizationRequestOpts;
}
}
exports.OpenID4VCIClient = OpenID4VCIClient;
//# sourceMappingURL=OpenID4VCIClient.js.map