@sphereon/oid4vci-client 0.8.2-next.48 → 0.8.2-next.87
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/AccessTokenClient.d.ts +0 -1
- package/dist/AccessTokenClient.d.ts.map +1 -1
- package/dist/AccessTokenClient.js +2 -9
- package/dist/AccessTokenClient.js.map +1 -1
- package/dist/AuthorizationCodeClient.d.ts +9 -0
- package/dist/AuthorizationCodeClient.d.ts.map +1 -0
- package/dist/AuthorizationCodeClient.js +124 -0
- package/dist/AuthorizationCodeClient.js.map +1 -0
- package/dist/CredentialOfferClient.d.ts.map +1 -1
- package/dist/CredentialOfferClient.js +3 -1
- package/dist/CredentialOfferClient.js.map +1 -1
- package/dist/CredentialRequestClient.d.ts +2 -0
- package/dist/CredentialRequestClient.d.ts.map +1 -1
- package/dist/CredentialRequestClient.js +9 -7
- package/dist/CredentialRequestClient.js.map +1 -1
- package/dist/OpenID4VCIClient.d.ts +50 -29
- package/dist/OpenID4VCIClient.d.ts.map +1 -1
- package/dist/OpenID4VCIClient.js +191 -190
- package/dist/OpenID4VCIClient.js.map +1 -1
- package/dist/functions/AuthorizationUtil.d.ts +3 -0
- package/dist/functions/AuthorizationUtil.d.ts.map +1 -0
- package/dist/functions/AuthorizationUtil.js +22 -0
- package/dist/functions/AuthorizationUtil.js.map +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/types/index.d.ts +1 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +2 -0
- package/dist/types/index.js.map +1 -0
- package/lib/AccessTokenClient.ts +5 -11
- package/lib/AuthorizationCodeClient.ts +151 -0
- package/lib/CredentialOfferClient.ts +4 -1
- package/lib/CredentialRequestClient.ts +13 -4
- package/lib/OpenID4VCIClient.ts +250 -228
- package/lib/__tests__/AccessTokenClient.spec.ts +2 -0
- package/lib/__tests__/CredentialRequestClient.spec.ts +10 -2
- package/lib/__tests__/EBSIE2E.spec.test.ts +8 -6
- package/lib/__tests__/OpenID4VCIClient.spec.ts +115 -79
- package/lib/__tests__/OpenID4VCIClientPAR.spec.ts +59 -49
- package/lib/__tests__/SdJwt.spec.ts +2 -0
- package/lib/__tests__/SphereonE2E.spec.test.ts +2 -2
- package/lib/functions/AuthorizationUtil.ts +18 -0
- package/lib/index.ts +1 -0
- package/lib/types/index.ts +0 -0
- package/package.json +3 -3
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.generateMissingPKCEOpts = void 0;
|
|
4
|
+
const oid4vci_common_1 = require("@sphereon/oid4vci-common");
|
|
5
|
+
const generateMissingPKCEOpts = (pkce) => {
|
|
6
|
+
if (pkce.disabled) {
|
|
7
|
+
return pkce;
|
|
8
|
+
}
|
|
9
|
+
if (!pkce.codeChallengeMethod) {
|
|
10
|
+
pkce.codeChallengeMethod = oid4vci_common_1.CodeChallengeMethod.S256;
|
|
11
|
+
}
|
|
12
|
+
if (!pkce.codeVerifier) {
|
|
13
|
+
pkce.codeVerifier = (0, oid4vci_common_1.generateCodeVerifier)();
|
|
14
|
+
}
|
|
15
|
+
(0, oid4vci_common_1.assertValidCodeVerifier)(pkce.codeVerifier);
|
|
16
|
+
if (!pkce.codeChallenge) {
|
|
17
|
+
pkce.codeChallenge = (0, oid4vci_common_1.createCodeChallenge)(pkce.codeVerifier, pkce.codeChallengeMethod);
|
|
18
|
+
}
|
|
19
|
+
return pkce;
|
|
20
|
+
};
|
|
21
|
+
exports.generateMissingPKCEOpts = generateMissingPKCEOpts;
|
|
22
|
+
//# sourceMappingURL=AuthorizationUtil.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AuthorizationUtil.js","sourceRoot":"","sources":["../../lib/functions/AuthorizationUtil.ts"],"names":[],"mappings":";;;AAAA,6DAA6I;AAEtI,MAAM,uBAAuB,GAAG,CAAC,IAAc,EAAE,EAAE;IACxD,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;QAClB,OAAO,IAAI,CAAC;IACd,CAAC;IACD,IAAI,CAAC,IAAI,CAAC,mBAAmB,EAAE,CAAC;QAC9B,IAAI,CAAC,mBAAmB,GAAG,oCAAmB,CAAC,IAAI,CAAC;IACtD,CAAC;IACD,IAAI,CAAC,IAAI,CAAC,YAAY,EAAE,CAAC;QACvB,IAAI,CAAC,YAAY,GAAG,IAAA,qCAAoB,GAAE,CAAC;IAC7C,CAAC;IACD,IAAA,wCAAuB,EAAC,IAAI,CAAC,YAAY,CAAC,CAAC;IAC3C,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE,CAAC;QACxB,IAAI,CAAC,aAAa,GAAG,IAAA,oCAAmB,EAAC,IAAI,CAAC,YAAY,EAAE,IAAI,CAAC,mBAAmB,CAAC,CAAC;IACxF,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC,CAAC;AAfW,QAAA,uBAAuB,2BAelC"}
|
package/dist/index.d.ts
CHANGED
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../lib/index.ts"],"names":[],"mappings":"AAAA,cAAc,qBAAqB,CAAC;AACpC,cAAc,yBAAyB,CAAC;AACxC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,kCAAkC,CAAC;AACjD,cAAc,aAAa,CAAC;AAC5B,cAAc,kBAAkB,CAAC;AACjC,cAAc,oBAAoB,CAAC;AACnC,cAAc,4BAA4B,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../lib/index.ts"],"names":[],"mappings":"AAAA,cAAc,qBAAqB,CAAC;AACpC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,yBAAyB,CAAC;AACxC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,kCAAkC,CAAC;AACjD,cAAc,aAAa,CAAC;AAC5B,cAAc,kBAAkB,CAAC;AACjC,cAAc,oBAAoB,CAAC;AACnC,cAAc,4BAA4B,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -15,6 +15,7 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
|
15
15
|
};
|
|
16
16
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
17
|
__exportStar(require("./AccessTokenClient"), exports);
|
|
18
|
+
__exportStar(require("./CredentialRequestClient"), exports);
|
|
18
19
|
__exportStar(require("./CredentialOfferClient"), exports);
|
|
19
20
|
__exportStar(require("./CredentialRequestClient"), exports);
|
|
20
21
|
__exportStar(require("./CredentialRequestClientBuilder"), exports);
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../lib/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,sDAAoC;AACpC,0DAAwC;AACxC,4DAA0C;AAC1C,mEAAiD;AACjD,8CAA4B;AAC5B,mDAAiC;AACjC,qDAAmC;AACnC,6DAA2C"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../lib/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,sDAAoC;AACpC,4DAA0C;AAC1C,0DAAwC;AACxC,4DAA0C;AAC1C,mEAAiD;AACjD,8CAA4B;AAC5B,mDAAiC;AACjC,qDAAmC;AACnC,6DAA2C"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../lib/types/index.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../lib/types/index.ts"],"names":[],"mappings":""}
|
package/lib/AccessTokenClient.ts
CHANGED
|
@@ -9,6 +9,7 @@ import {
|
|
|
9
9
|
getIssuerFromCredentialOfferPayload,
|
|
10
10
|
GrantTypes,
|
|
11
11
|
IssuerOpts,
|
|
12
|
+
JsonURIMode,
|
|
12
13
|
OpenIDResponse,
|
|
13
14
|
PRE_AUTH_CODE_LITERAL,
|
|
14
15
|
TokenErrorResponse,
|
|
@@ -176,14 +177,6 @@ export class AccessTokenClient {
|
|
|
176
177
|
throw new Error('Authorization flow requires the code to be present');
|
|
177
178
|
}
|
|
178
179
|
}
|
|
179
|
-
|
|
180
|
-
private assertNonEmptyRedirectUri(accessTokenRequest: AccessTokenRequest): void {
|
|
181
|
-
if (!accessTokenRequest.redirect_uri) {
|
|
182
|
-
debug('No redirect_uri present, whilst it is required');
|
|
183
|
-
throw new Error('Authorization flow requires the redirect_uri to be present');
|
|
184
|
-
}
|
|
185
|
-
}
|
|
186
|
-
|
|
187
180
|
private validate(accessTokenRequest: AccessTokenRequest, isPinRequired?: boolean): void {
|
|
188
181
|
if (accessTokenRequest.grant_type === GrantTypes.PRE_AUTHORIZED_CODE) {
|
|
189
182
|
this.assertPreAuthorizedGrantType(accessTokenRequest.grant_type);
|
|
@@ -193,14 +186,13 @@ export class AccessTokenClient {
|
|
|
193
186
|
this.assertAuthorizationGrantType(accessTokenRequest.grant_type);
|
|
194
187
|
this.assertNonEmptyCodeVerifier(accessTokenRequest);
|
|
195
188
|
this.assertNonEmptyCode(accessTokenRequest);
|
|
196
|
-
this.assertNonEmptyRedirectUri(accessTokenRequest);
|
|
197
189
|
} else {
|
|
198
190
|
this.throwNotSupportedFlow();
|
|
199
191
|
}
|
|
200
192
|
}
|
|
201
193
|
|
|
202
194
|
private async sendAuthCode(requestTokenURL: string, accessTokenRequest: AccessTokenRequest): Promise<OpenIDResponse<AccessTokenResponse>> {
|
|
203
|
-
return await formPost(requestTokenURL, convertJsonToURI(accessTokenRequest));
|
|
195
|
+
return await formPost(requestTokenURL, convertJsonToURI(accessTokenRequest, { mode: JsonURIMode.X_FORM_WWW_URLENCODED }));
|
|
204
196
|
}
|
|
205
197
|
|
|
206
198
|
public static determineTokenURL({
|
|
@@ -236,7 +228,9 @@ export class AccessTokenClient {
|
|
|
236
228
|
|
|
237
229
|
private static creatTokenURLFromURL(url: string, allowInsecureEndpoints?: boolean, tokenEndpoint?: string): string {
|
|
238
230
|
if (allowInsecureEndpoints !== true && url.startsWith('http:')) {
|
|
239
|
-
throw Error(
|
|
231
|
+
throw Error(
|
|
232
|
+
`Unprotected token endpoints are not allowed ${url}. Use the 'allowInsecureEndpoints' param if you really need this for dev/testing!`,
|
|
233
|
+
);
|
|
240
234
|
}
|
|
241
235
|
const hostname = url.replace(/https?:\/\//, '').replace(/\/$/, '');
|
|
242
236
|
const endpoint = tokenEndpoint ? (tokenEndpoint.startsWith('/') ? tokenEndpoint : tokenEndpoint.substring(1)) : '/token';
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
import {
|
|
2
|
+
AuthorizationDetails,
|
|
3
|
+
AuthorizationRequestOpts,
|
|
4
|
+
CodeChallengeMethod,
|
|
5
|
+
convertJsonToURI,
|
|
6
|
+
CredentialOfferRequestWithBaseUrl,
|
|
7
|
+
CredentialSupported,
|
|
8
|
+
EndpointMetadataResult,
|
|
9
|
+
JsonURIMode,
|
|
10
|
+
PARMode,
|
|
11
|
+
PKCEOpts,
|
|
12
|
+
PushedAuthorizationResponse,
|
|
13
|
+
ResponseType,
|
|
14
|
+
} from '@sphereon/oid4vci-common';
|
|
15
|
+
import { formPost } from '@sphereon/oid4vci-common';
|
|
16
|
+
import Debug from 'debug';
|
|
17
|
+
|
|
18
|
+
const debug = Debug('sphereon:oid4vci');
|
|
19
|
+
|
|
20
|
+
export const createAuthorizationRequestUrl = async ({
|
|
21
|
+
pkce,
|
|
22
|
+
endpointMetadata,
|
|
23
|
+
authorizationRequest,
|
|
24
|
+
credentialOffer,
|
|
25
|
+
credentialsSupported,
|
|
26
|
+
}: {
|
|
27
|
+
pkce: PKCEOpts;
|
|
28
|
+
endpointMetadata: EndpointMetadataResult;
|
|
29
|
+
authorizationRequest: AuthorizationRequestOpts;
|
|
30
|
+
credentialOffer?: CredentialOfferRequestWithBaseUrl;
|
|
31
|
+
credentialsSupported?: CredentialSupported[];
|
|
32
|
+
}): Promise<string> => {
|
|
33
|
+
const { redirectUri, clientId } = authorizationRequest;
|
|
34
|
+
let { scope, authorizationDetails } = authorizationRequest;
|
|
35
|
+
const parMode = endpointMetadata?.credentialIssuerMetadata?.require_pushed_authorization_requests
|
|
36
|
+
? PARMode.REQUIRE
|
|
37
|
+
: authorizationRequest.parMode ?? PARMode.AUTO;
|
|
38
|
+
// Scope and authorization_details can be used in the same authorization request
|
|
39
|
+
// https://datatracker.ietf.org/doc/html/draft-ietf-oauth-rar-23#name-relationship-to-scope-param
|
|
40
|
+
if (!scope && !authorizationDetails) {
|
|
41
|
+
if (!credentialOffer) {
|
|
42
|
+
throw Error('Please provide a scope or authorization_details if no credential offer is present');
|
|
43
|
+
}
|
|
44
|
+
const creds = credentialOffer.credential_offer.credentials;
|
|
45
|
+
|
|
46
|
+
// FIXME: complains about VCT for sd-jwt
|
|
47
|
+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
48
|
+
// @ts-ignore
|
|
49
|
+
authorizationDetails = creds
|
|
50
|
+
.flatMap((cred) => (typeof cred === 'string' ? credentialsSupported : (cred as CredentialSupported)))
|
|
51
|
+
.filter((cred) => !!cred)
|
|
52
|
+
.map((cred) => {
|
|
53
|
+
return {
|
|
54
|
+
...cred,
|
|
55
|
+
type: 'openid_credential',
|
|
56
|
+
locations: [endpointMetadata.issuer],
|
|
57
|
+
|
|
58
|
+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
59
|
+
// @ts-ignore
|
|
60
|
+
format: cred!.format,
|
|
61
|
+
} satisfies AuthorizationDetails;
|
|
62
|
+
});
|
|
63
|
+
if (!authorizationDetails || authorizationDetails.length === 0) {
|
|
64
|
+
throw Error(`Could not create authorization details from credential offer. Please pass in explicit details`);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
if (!endpointMetadata?.authorization_endpoint) {
|
|
68
|
+
throw Error('Server metadata does not contain authorization endpoint');
|
|
69
|
+
}
|
|
70
|
+
const parEndpoint = endpointMetadata.credentialIssuerMetadata?.pushed_authorization_request_endpoint;
|
|
71
|
+
|
|
72
|
+
// add 'openid' scope if not present
|
|
73
|
+
if (!scope?.includes('openid')) {
|
|
74
|
+
scope = ['openid', scope].filter((s) => !!s).join(' ');
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
let queryObj: { [key: string]: string } | PushedAuthorizationResponse = {
|
|
78
|
+
response_type: ResponseType.AUTH_CODE,
|
|
79
|
+
...(!pkce.disabled && {
|
|
80
|
+
code_challenge_method: pkce.codeChallengeMethod ?? CodeChallengeMethod.S256,
|
|
81
|
+
code_challenge: pkce.codeChallenge,
|
|
82
|
+
}),
|
|
83
|
+
authorization_details: JSON.stringify(handleAuthorizationDetails(endpointMetadata, authorizationDetails)),
|
|
84
|
+
...(redirectUri && { redirect_uri: redirectUri }),
|
|
85
|
+
...(clientId && { client_id: clientId }),
|
|
86
|
+
...(credentialOffer?.issuerState && { issuer_state: credentialOffer.issuerState }),
|
|
87
|
+
scope,
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
if (!parEndpoint && parMode === PARMode.REQUIRE) {
|
|
91
|
+
throw Error(`PAR mode is set to required by Authorization Server does not support PAR!`);
|
|
92
|
+
} else if (parEndpoint && parMode !== PARMode.NEVER) {
|
|
93
|
+
debug(`USING PAR with endpoint ${parEndpoint}`);
|
|
94
|
+
const parResponse = await formPost<PushedAuthorizationResponse>(parEndpoint, new URLSearchParams(queryObj));
|
|
95
|
+
if (parResponse.errorBody || !parResponse.successBody) {
|
|
96
|
+
throw Error(`PAR error`);
|
|
97
|
+
}
|
|
98
|
+
debug(`PAR response: ${(parResponse.successBody, null, 2)}`);
|
|
99
|
+
queryObj = { request_uri: parResponse.successBody.request_uri };
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
debug(`Object that will become query params: ` + JSON.stringify(queryObj, null, 2));
|
|
103
|
+
const url = convertJsonToURI(queryObj, {
|
|
104
|
+
baseUrl: endpointMetadata.authorization_endpoint,
|
|
105
|
+
uriTypeProperties: ['client_id', 'request_uri', 'redirect_uri', 'scope', 'authorization_details', 'issuer_state'],
|
|
106
|
+
// arrayTypeProperties: ['authorization_details'],
|
|
107
|
+
mode: JsonURIMode.X_FORM_WWW_URLENCODED,
|
|
108
|
+
// We do not add the version here, as this always needs to be form encoded
|
|
109
|
+
});
|
|
110
|
+
debug(`Authorization Request URL: ${url}`);
|
|
111
|
+
return url;
|
|
112
|
+
};
|
|
113
|
+
|
|
114
|
+
const handleAuthorizationDetails = (
|
|
115
|
+
endpointMetadata: EndpointMetadataResult,
|
|
116
|
+
authorizationDetails?: AuthorizationDetails | AuthorizationDetails[],
|
|
117
|
+
): AuthorizationDetails | AuthorizationDetails[] | undefined => {
|
|
118
|
+
if (authorizationDetails) {
|
|
119
|
+
if (typeof authorizationDetails === 'string') {
|
|
120
|
+
// backwards compat for older versions of the lib
|
|
121
|
+
return authorizationDetails;
|
|
122
|
+
}
|
|
123
|
+
if (Array.isArray(authorizationDetails)) {
|
|
124
|
+
return authorizationDetails
|
|
125
|
+
.filter((value) => typeof value !== 'string')
|
|
126
|
+
.map((value) => handleLocations(endpointMetadata, typeof value === 'string' ? value : { ...value }));
|
|
127
|
+
} else {
|
|
128
|
+
return handleLocations(endpointMetadata, { ...authorizationDetails });
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
return authorizationDetails;
|
|
132
|
+
};
|
|
133
|
+
|
|
134
|
+
const handleLocations = (endpointMetadata: EndpointMetadataResult, authorizationDetails: AuthorizationDetails) => {
|
|
135
|
+
if (typeof authorizationDetails === 'string') {
|
|
136
|
+
// backwards compat for older versions of the lib
|
|
137
|
+
return authorizationDetails;
|
|
138
|
+
}
|
|
139
|
+
if (authorizationDetails && (endpointMetadata.credentialIssuerMetadata?.authorization_server || endpointMetadata.authorization_endpoint)) {
|
|
140
|
+
if (authorizationDetails.locations) {
|
|
141
|
+
if (Array.isArray(authorizationDetails.locations)) {
|
|
142
|
+
authorizationDetails.locations.push(endpointMetadata.issuer);
|
|
143
|
+
} else {
|
|
144
|
+
authorizationDetails.locations = [authorizationDetails.locations as string, endpointMetadata.issuer];
|
|
145
|
+
}
|
|
146
|
+
} else {
|
|
147
|
+
authorizationDetails.locations = [endpointMetadata.issuer];
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
return authorizationDetails;
|
|
151
|
+
};
|
|
@@ -5,6 +5,7 @@ import {
|
|
|
5
5
|
CredentialOfferRequestWithBaseUrl,
|
|
6
6
|
CredentialOfferV1_0_11,
|
|
7
7
|
determineSpecVersionFromURI,
|
|
8
|
+
getClientIdFromCredentialOfferPayload,
|
|
8
9
|
OpenId4VCIVersion,
|
|
9
10
|
toUniformCredentialOfferRequest,
|
|
10
11
|
} from '@sphereon/oid4vci-common';
|
|
@@ -43,16 +44,18 @@ export class CredentialOfferClient {
|
|
|
43
44
|
throw Error('Either a credential_offer or credential_offer_uri should be present in ' + uri);
|
|
44
45
|
}
|
|
45
46
|
}
|
|
47
|
+
|
|
46
48
|
const request = await toUniformCredentialOfferRequest(credentialOffer, {
|
|
47
49
|
...opts,
|
|
48
50
|
version,
|
|
49
51
|
});
|
|
50
|
-
|
|
52
|
+
const clientId = getClientIdFromCredentialOfferPayload(request.credential_offer);
|
|
51
53
|
const grants = request.credential_offer?.grants;
|
|
52
54
|
|
|
53
55
|
return {
|
|
54
56
|
scheme,
|
|
55
57
|
baseUrl,
|
|
58
|
+
clientId,
|
|
56
59
|
...request,
|
|
57
60
|
...(grants?.authorization_code?.issuer_state && { issuerState: grants.authorization_code.issuer_state }),
|
|
58
61
|
...(grants?.['urn:ietf:params:oauth:grant-type:pre-authorized_code']?.['pre-authorized_code'] && {
|
|
@@ -78,11 +78,12 @@ export class CredentialRequestClient {
|
|
|
78
78
|
public async acquireCredentialsUsingProof<DIDDoc>(opts: {
|
|
79
79
|
proofInput: ProofOfPossessionBuilder<DIDDoc> | ProofOfPossession;
|
|
80
80
|
credentialTypes?: string | string[];
|
|
81
|
+
context?: string[];
|
|
81
82
|
format?: CredentialFormat | OID4VCICredentialFormat;
|
|
82
83
|
}): Promise<OpenIDResponse<CredentialResponse>> {
|
|
83
|
-
const { credentialTypes, proofInput, format } = opts;
|
|
84
|
+
const { credentialTypes, proofInput, format, context } = opts;
|
|
84
85
|
|
|
85
|
-
const request = await this.createCredentialRequest({ proofInput, credentialTypes, format, version: this.version() });
|
|
86
|
+
const request = await this.createCredentialRequest({ proofInput, credentialTypes, context, format, version: this.version() });
|
|
86
87
|
return await this.acquireCredentialsUsingRequest(request);
|
|
87
88
|
}
|
|
88
89
|
|
|
@@ -133,6 +134,7 @@ export class CredentialRequestClient {
|
|
|
133
134
|
public async createCredentialRequest<DIDDoc>(opts: {
|
|
134
135
|
proofInput: ProofOfPossessionBuilder<DIDDoc> | ProofOfPossession;
|
|
135
136
|
credentialTypes?: string | string[];
|
|
137
|
+
context?: string[];
|
|
136
138
|
format?: CredentialFormat | OID4VCICredentialFormat;
|
|
137
139
|
version: OpenId4VCIVersion;
|
|
138
140
|
}): Promise<UniformCredentialRequest> {
|
|
@@ -165,13 +167,20 @@ export class CredentialRequestClient {
|
|
|
165
167
|
proof,
|
|
166
168
|
};
|
|
167
169
|
} else if (format === 'jwt_vc_json-ld' || format === 'ldp_vc') {
|
|
170
|
+
if (this.version() >= OpenId4VCIVersion.VER_1_0_12 && !opts.context) {
|
|
171
|
+
throw Error('No @context value present, but it is required');
|
|
172
|
+
}
|
|
173
|
+
|
|
168
174
|
return {
|
|
169
175
|
format,
|
|
170
176
|
proof,
|
|
177
|
+
|
|
178
|
+
// Ignored because v11 does not have the context value, but it is required in v12
|
|
179
|
+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
180
|
+
// @ts-ignore
|
|
171
181
|
credential_definition: {
|
|
172
182
|
types,
|
|
173
|
-
|
|
174
|
-
'@context': [],
|
|
183
|
+
...(opts.context && { '@context': opts.context }),
|
|
175
184
|
},
|
|
176
185
|
};
|
|
177
186
|
} else if (format === 'vc+sd-jwt') {
|