@sphereon/oid4vci-client 0.12.1-next.2 → 0.12.1-next.21

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.
Files changed (60) hide show
  1. package/dist/AccessTokenClient.d.ts.map +1 -1
  2. package/dist/AccessTokenClient.js +7 -5
  3. package/dist/AccessTokenClient.js.map +1 -1
  4. package/dist/AccessTokenClientV1_0_11.d.ts.map +1 -1
  5. package/dist/AccessTokenClientV1_0_11.js +7 -5
  6. package/dist/AccessTokenClientV1_0_11.js.map +1 -1
  7. package/dist/CredentialRequestClient.d.ts +3 -2
  8. package/dist/CredentialRequestClient.d.ts.map +1 -1
  9. package/dist/CredentialRequestClient.js.map +1 -1
  10. package/dist/CredentialRequestClientBuilder.d.ts +7 -15
  11. package/dist/CredentialRequestClientBuilder.d.ts.map +1 -1
  12. package/dist/CredentialRequestClientBuilder.js +79 -55
  13. package/dist/CredentialRequestClientBuilder.js.map +1 -1
  14. package/dist/CredentialRequestClientBuilderV1_0_13.d.ts +51 -0
  15. package/dist/CredentialRequestClientBuilderV1_0_13.d.ts.map +1 -0
  16. package/dist/CredentialRequestClientBuilderV1_0_13.js +130 -0
  17. package/dist/CredentialRequestClientBuilderV1_0_13.js.map +1 -0
  18. package/dist/OpenID4VCIClient.d.ts +3 -1
  19. package/dist/OpenID4VCIClient.d.ts.map +1 -1
  20. package/dist/OpenID4VCIClient.js +22 -13
  21. package/dist/OpenID4VCIClient.js.map +1 -1
  22. package/dist/OpenID4VCIClientV1_0_11.d.ts +2 -1
  23. package/dist/OpenID4VCIClientV1_0_11.d.ts.map +1 -1
  24. package/dist/OpenID4VCIClientV1_0_11.js +13 -4
  25. package/dist/OpenID4VCIClientV1_0_11.js.map +1 -1
  26. package/dist/OpenID4VCIClientV1_0_13.d.ts +2 -1
  27. package/dist/OpenID4VCIClientV1_0_13.d.ts.map +1 -1
  28. package/dist/OpenID4VCIClientV1_0_13.js +16 -7
  29. package/dist/OpenID4VCIClientV1_0_13.js.map +1 -1
  30. package/dist/functions/AccessTokenUtil.d.ts +5 -0
  31. package/dist/functions/AccessTokenUtil.d.ts.map +1 -0
  32. package/dist/functions/AccessTokenUtil.js +55 -0
  33. package/dist/functions/AccessTokenUtil.js.map +1 -0
  34. package/dist/functions/index.d.ts +2 -0
  35. package/dist/functions/index.d.ts.map +1 -1
  36. package/dist/functions/index.js +2 -0
  37. package/dist/functions/index.js.map +1 -1
  38. package/dist/index.d.ts +1 -0
  39. package/dist/index.d.ts.map +1 -1
  40. package/dist/index.js +1 -0
  41. package/dist/index.js.map +1 -1
  42. package/lib/AccessTokenClient.ts +5 -4
  43. package/lib/AccessTokenClientV1_0_11.ts +6 -3
  44. package/lib/CredentialRequestClient.ts +3 -2
  45. package/lib/CredentialRequestClientBuilder.ts +98 -67
  46. package/lib/CredentialRequestClientBuilderV1_0_13.ts +173 -0
  47. package/lib/OpenID4VCIClient.ts +27 -6
  48. package/lib/OpenID4VCIClientV1_0_11.ts +19 -1
  49. package/lib/OpenID4VCIClientV1_0_13.ts +19 -1
  50. package/lib/__tests__/CredentialRequestClient.spec.ts +8 -13
  51. package/lib/__tests__/CredentialRequestClientBuilder.spec.ts +40 -2
  52. package/lib/__tests__/CredentialRequestClientV1_0_11.spec.ts +96 -0
  53. package/lib/__tests__/IT.spec.ts +148 -111
  54. package/lib/__tests__/MetadataMocks.ts +35 -0
  55. package/lib/__tests__/ProofOfPossessionBuilder.spec.ts +85 -0
  56. package/lib/__tests__/SdJwt.spec.ts +103 -0
  57. package/lib/functions/AccessTokenUtil.ts +45 -0
  58. package/lib/functions/index.ts +2 -0
  59. package/lib/index.ts +1 -0
  60. package/package.json +3 -3
@@ -0,0 +1,173 @@
1
+ import {
2
+ AccessTokenResponse,
3
+ CredentialIssuerMetadataV1_0_13,
4
+ CredentialOfferPayloadV1_0_13,
5
+ CredentialOfferRequestWithBaseUrl,
6
+ determineSpecVersionFromOffer,
7
+ EndpointMetadata,
8
+ ExperimentalSubjectIssuance,
9
+ getIssuerFromCredentialOfferPayload,
10
+ OID4VCICredentialFormat,
11
+ OpenId4VCIVersion,
12
+ UniformCredentialOfferRequest,
13
+ } from '@sphereon/oid4vci-common';
14
+ import { CredentialFormat } from '@sphereon/ssi-types';
15
+
16
+ import { CredentialOfferClient } from './CredentialOfferClient';
17
+ import { CredentialRequestClient } from './CredentialRequestClient';
18
+
19
+ export class CredentialRequestClientBuilderV1_0_13 {
20
+ credentialEndpoint?: string;
21
+ deferredCredentialEndpoint?: string;
22
+ deferredCredentialAwait = false;
23
+ deferredCredentialIntervalInMS = 5000;
24
+ credentialIdentifier?: string;
25
+ credentialTypes?: string[] = [];
26
+ format?: CredentialFormat | OID4VCICredentialFormat;
27
+ token?: string;
28
+ version?: OpenId4VCIVersion;
29
+ subjectIssuance?: ExperimentalSubjectIssuance;
30
+
31
+ public static fromCredentialIssuer({
32
+ credentialIssuer,
33
+ metadata,
34
+ version,
35
+ credentialIdentifier,
36
+ credentialTypes,
37
+ }: {
38
+ credentialIssuer: string;
39
+ metadata?: EndpointMetadata;
40
+ version?: OpenId4VCIVersion;
41
+ credentialIdentifier?: string;
42
+ credentialTypes?: string | string[];
43
+ }): CredentialRequestClientBuilderV1_0_13 {
44
+ const issuer = credentialIssuer;
45
+ const builder = new CredentialRequestClientBuilderV1_0_13();
46
+ builder.withVersion(version ?? OpenId4VCIVersion.VER_1_0_13);
47
+ builder.withCredentialEndpoint(metadata?.credential_endpoint ?? (issuer.endsWith('/') ? `${issuer}credential` : `${issuer}/credential`));
48
+ if (metadata?.deferred_credential_endpoint) {
49
+ builder.withDeferredCredentialEndpoint(metadata.deferred_credential_endpoint);
50
+ }
51
+ if (credentialIdentifier) {
52
+ builder.withCredentialIdentifier(credentialIdentifier);
53
+ }
54
+ if (credentialTypes) {
55
+ builder.withCredentialType(credentialTypes);
56
+ }
57
+ return builder;
58
+ }
59
+
60
+ public static async fromURI({ uri, metadata }: { uri: string; metadata?: EndpointMetadata }): Promise<CredentialRequestClientBuilderV1_0_13> {
61
+ const offer = await CredentialOfferClient.fromURI(uri);
62
+ return CredentialRequestClientBuilderV1_0_13.fromCredentialOfferRequest({ request: offer, ...offer, metadata, version: offer.version });
63
+ }
64
+
65
+ public static fromCredentialOfferRequest(opts: {
66
+ request: UniformCredentialOfferRequest;
67
+ scheme?: string;
68
+ baseUrl?: string;
69
+ version?: OpenId4VCIVersion;
70
+ metadata?: EndpointMetadata;
71
+ }): CredentialRequestClientBuilderV1_0_13 {
72
+ const { request, metadata } = opts;
73
+ const version = opts.version ?? request.version ?? determineSpecVersionFromOffer(request.original_credential_offer);
74
+ if (version < OpenId4VCIVersion.VER_1_0_13) {
75
+ throw new Error('Versions below v1.0.13 (draft 13) are not supported.');
76
+ }
77
+ const builder = new CredentialRequestClientBuilderV1_0_13();
78
+ const issuer = getIssuerFromCredentialOfferPayload(request.credential_offer) ?? (metadata?.issuer as string);
79
+ builder.withVersion(version);
80
+ builder.withCredentialEndpoint(metadata?.credential_endpoint ?? (issuer.endsWith('/') ? `${issuer}credential` : `${issuer}/credential`));
81
+ if (metadata?.deferred_credential_endpoint) {
82
+ builder.withDeferredCredentialEndpoint(metadata.deferred_credential_endpoint);
83
+ }
84
+ const ids: string[] = (request.credential_offer as CredentialOfferPayloadV1_0_13).credential_configuration_ids;
85
+ // if there's only one in the offer, we pre-select it. if not, you should provide the credentialType
86
+ if (ids.length && ids.length === 1) {
87
+ builder.withCredentialIdentifier(ids[0]);
88
+ }
89
+ return builder;
90
+ }
91
+
92
+ public static fromCredentialOffer({
93
+ credentialOffer,
94
+ metadata,
95
+ }: {
96
+ credentialOffer: CredentialOfferRequestWithBaseUrl;
97
+ metadata?: EndpointMetadata;
98
+ }): CredentialRequestClientBuilderV1_0_13 {
99
+ return CredentialRequestClientBuilderV1_0_13.fromCredentialOfferRequest({
100
+ request: credentialOffer,
101
+ metadata,
102
+ version: credentialOffer.version,
103
+ });
104
+ }
105
+
106
+ public withCredentialEndpointFromMetadata(metadata: CredentialIssuerMetadataV1_0_13): this {
107
+ this.credentialEndpoint = metadata.credential_endpoint;
108
+ return this;
109
+ }
110
+
111
+ public withCredentialEndpoint(credentialEndpoint: string): this {
112
+ this.credentialEndpoint = credentialEndpoint;
113
+ return this;
114
+ }
115
+
116
+ public withDeferredCredentialEndpointFromMetadata(metadata: CredentialIssuerMetadataV1_0_13): this {
117
+ this.deferredCredentialEndpoint = metadata.deferred_credential_endpoint;
118
+ return this;
119
+ }
120
+
121
+ public withDeferredCredentialEndpoint(deferredCredentialEndpoint: string): this {
122
+ this.deferredCredentialEndpoint = deferredCredentialEndpoint;
123
+ return this;
124
+ }
125
+
126
+ public withDeferredCredentialAwait(deferredCredentialAwait: boolean, deferredCredentialIntervalInMS?: number): this {
127
+ this.deferredCredentialAwait = deferredCredentialAwait;
128
+ this.deferredCredentialIntervalInMS = deferredCredentialIntervalInMS ?? 5000;
129
+ return this;
130
+ }
131
+
132
+ public withCredentialIdentifier(credentialIdentifier: string): this {
133
+ this.credentialIdentifier = credentialIdentifier;
134
+ return this;
135
+ }
136
+
137
+ public withCredentialType(credentialTypes: string | string[]): this {
138
+ this.credentialTypes = Array.isArray(credentialTypes) ? credentialTypes : [credentialTypes];
139
+ return this;
140
+ }
141
+
142
+ public withFormat(format: CredentialFormat | OID4VCICredentialFormat): this {
143
+ this.format = format;
144
+ return this;
145
+ }
146
+
147
+ public withSubjectIssuance(subjectIssuance: ExperimentalSubjectIssuance): this {
148
+ this.subjectIssuance = subjectIssuance;
149
+ return this;
150
+ }
151
+
152
+ public withToken(accessToken: string): this {
153
+ this.token = accessToken;
154
+ return this;
155
+ }
156
+
157
+ public withTokenFromResponse(response: AccessTokenResponse): this {
158
+ this.token = response.access_token;
159
+ return this;
160
+ }
161
+
162
+ public withVersion(version: OpenId4VCIVersion): this {
163
+ this.version = version;
164
+ return this;
165
+ }
166
+
167
+ public build(): CredentialRequestClient {
168
+ if (!this.version) {
169
+ this.withVersion(OpenId4VCIVersion.VER_1_0_11);
170
+ }
171
+ return new CredentialRequestClient(this);
172
+ }
173
+ }
@@ -3,6 +3,7 @@ import {
3
3
  Alg,
4
4
  AuthorizationRequestOpts,
5
5
  AuthorizationResponse,
6
+ AuthorizationServerOpts,
6
7
  AuthzFlowType,
7
8
  CodeChallengeMethod,
8
9
  CredentialConfigurationSupported,
@@ -41,7 +42,7 @@ import { createAuthorizationRequestUrl } from './AuthorizationCodeClient';
41
42
  import { createAuthorizationRequestUrlV1_0_11 } from './AuthorizationCodeClientV1_0_11';
42
43
  import { CredentialOfferClient } from './CredentialOfferClient';
43
44
  import { CredentialRequestOpts } from './CredentialRequestClient';
44
- import { CredentialRequestClientBuilder } from './CredentialRequestClientBuilder';
45
+ import { CredentialRequestClientBuilderV1_0_13 } from './CredentialRequestClientBuilderV1_0_13';
45
46
  import { CredentialRequestClientBuilderV1_0_11 } from './CredentialRequestClientBuilderV1_0_11';
46
47
  import { MetadataClient } from './MetadataClient';
47
48
  import { OpenID4VCIClientStateV1_0_11 } from './OpenID4VCIClientV1_0_11';
@@ -273,8 +274,10 @@ export class OpenID4VCIClient {
273
274
  authorizationResponse?: string | AuthorizationResponse; // Pass in an auth response, either as URI/redirect, or object
274
275
  code?: string; // Directly pass in a code from an auth response
275
276
  redirectUri?: string;
277
+ additionalRequestParams?: Record<string, any>;
278
+ asOpts?: AuthorizationServerOpts;
276
279
  }): Promise<AccessTokenResponse> {
277
- const { pin, clientId } = opts ?? {};
280
+ const { pin, clientId = this._state.clientId ?? this._state.authorizationRequestOpts?.clientId } = opts ?? {};
278
281
  let { redirectUri } = opts ?? {};
279
282
  if (opts?.authorizationResponse) {
280
283
  this._state.authorizationCodeResponse = { ...toAuthorizationResponsePayload(opts.authorizationResponse) };
@@ -288,6 +291,23 @@ export class OpenID4VCIClient {
288
291
  }
289
292
  this.assertIssuerData();
290
293
 
294
+ const asOpts: AuthorizationServerOpts = { ...opts?.asOpts };
295
+ const kid = asOpts.clientOpts?.kid ?? this._state.kid ?? this._state.authorizationRequestOpts?.requestObjectOpts?.kid;
296
+ const clientAssertionType =
297
+ asOpts.clientOpts?.clientAssertionType ??
298
+ (kid && clientId && typeof asOpts.clientOpts?.signCallbacks === 'function'
299
+ ? 'urn:ietf:params:oauth:client-assertion-type:jwt-bearer'
300
+ : undefined);
301
+ if (clientId) {
302
+ asOpts.clientOpts = {
303
+ ...asOpts.clientOpts,
304
+ clientId,
305
+ ...(kid && { kid }),
306
+ ...(clientAssertionType && { clientAssertionType }),
307
+ signCallbacks: asOpts.clientOpts?.signCallbacks ?? this._state.authorizationRequestOpts?.requestObjectOpts?.signCallbacks,
308
+ };
309
+ }
310
+
291
311
  if (clientId) {
292
312
  this._state.clientId = clientId;
293
313
  }
@@ -311,7 +331,8 @@ export class OpenID4VCIClient {
311
331
  ...(!this._state.pkce.disabled && { codeVerifier: this._state.pkce.codeVerifier }),
312
332
  code,
313
333
  redirectUri,
314
- asOpts: { clientId: this.clientId },
334
+ asOpts,
335
+ ...(opts?.additionalRequestParams && { additionalParams: opts.additionalRequestParams }),
315
336
  });
316
337
 
317
338
  if (response.errorBody) {
@@ -368,7 +389,7 @@ export class OpenID4VCIClient {
368
389
  if (jwk) this._state.jwk = jwk;
369
390
  if (kid) this._state.kid = kid;
370
391
 
371
- let requestBuilder: CredentialRequestClientBuilder | CredentialRequestClientBuilderV1_0_11;
392
+ let requestBuilder: CredentialRequestClientBuilderV1_0_13 | CredentialRequestClientBuilderV1_0_11;
372
393
  if (this.version() < OpenId4VCIVersion.VER_1_0_13) {
373
394
  requestBuilder = this.credentialOffer
374
395
  ? CredentialRequestClientBuilderV1_0_11.fromCredentialOffer({
@@ -383,11 +404,11 @@ export class OpenID4VCIClient {
383
404
  });
384
405
  } else {
385
406
  requestBuilder = this.credentialOffer
386
- ? CredentialRequestClientBuilder.fromCredentialOffer({
407
+ ? CredentialRequestClientBuilderV1_0_13.fromCredentialOffer({
387
408
  credentialOffer: this.credentialOffer,
388
409
  metadata: this.endpointMetadata,
389
410
  })
390
- : CredentialRequestClientBuilder.fromCredentialIssuer({
411
+ : CredentialRequestClientBuilderV1_0_13.fromCredentialIssuer({
391
412
  credentialIssuer: this.getIssuer(),
392
413
  credentialTypes,
393
414
  metadata: this.endpointMetadata,
@@ -3,6 +3,7 @@ import {
3
3
  Alg,
4
4
  AuthorizationRequestOpts,
5
5
  AuthorizationResponse,
6
+ AuthorizationServerOpts,
6
7
  AuthzFlowType,
7
8
  CodeChallengeMethod,
8
9
  CredentialConfigurationSupported,
@@ -259,6 +260,7 @@ export class OpenID4VCIClientV1_0_11 {
259
260
  authorizationResponse?: string | AuthorizationResponse; // Pass in an auth response, either as URI/redirect, or object
260
261
  code?: string; // Directly pass in a code from an auth response
261
262
  redirectUri?: string;
263
+ asOpts?: AuthorizationServerOpts;
262
264
  }): Promise<AccessTokenResponse> {
263
265
  const { pin, clientId } = opts ?? {};
264
266
  let { redirectUri } = opts ?? {};
@@ -288,6 +290,22 @@ export class OpenID4VCIClientV1_0_11 {
288
290
  if (this._state.authorizationRequestOpts?.redirectUri && !redirectUri) {
289
291
  redirectUri = this._state.authorizationRequestOpts.redirectUri;
290
292
  }
293
+ const asOpts: AuthorizationServerOpts = { ...opts?.asOpts };
294
+ const kid = asOpts.clientOpts?.kid ?? this._state.kid ?? this._state.authorizationRequestOpts?.requestObjectOpts?.kid;
295
+ const clientAssertionType =
296
+ asOpts.clientOpts?.clientAssertionType ??
297
+ (kid && clientId && typeof asOpts.clientOpts?.signCallbacks === 'function'
298
+ ? 'urn:ietf:params:oauth:client-assertion-type:jwt-bearer'
299
+ : undefined);
300
+ if (clientId) {
301
+ asOpts.clientOpts = {
302
+ ...asOpts.clientOpts,
303
+ clientId,
304
+ ...(kid && { kid }),
305
+ ...(clientAssertionType && { clientAssertionType }),
306
+ signCallbacks: asOpts.clientOpts?.signCallbacks ?? this._state.authorizationRequestOpts?.requestObjectOpts?.signCallbacks,
307
+ };
308
+ }
291
309
 
292
310
  const response = await accessTokenClient.acquireAccessToken({
293
311
  credentialOffer: this.credentialOffer,
@@ -297,7 +315,7 @@ export class OpenID4VCIClientV1_0_11 {
297
315
  ...(!this._state.pkce.disabled && { codeVerifier: this._state.pkce.codeVerifier }),
298
316
  code,
299
317
  redirectUri,
300
- asOpts: { clientId: this.clientId },
318
+ asOpts,
301
319
  });
302
320
 
303
321
  if (response.errorBody) {
@@ -3,6 +3,7 @@ import {
3
3
  Alg,
4
4
  AuthorizationRequestOpts,
5
5
  AuthorizationResponse,
6
+ AuthorizationServerOpts,
6
7
  AuthzFlowType,
7
8
  CodeChallengeMethod,
8
9
  CredentialConfigurationSupportedV1_0_13,
@@ -265,6 +266,7 @@ export class OpenID4VCIClientV1_0_13 {
265
266
  authorizationResponse?: string | AuthorizationResponse; // Pass in an auth response, either as URI/redirect, or object
266
267
  code?: string; // Directly pass in a code from an auth response
267
268
  redirectUri?: string;
269
+ asOpts?: AuthorizationServerOpts;
268
270
  }): Promise<AccessTokenResponse> {
269
271
  const { pin, clientId } = opts ?? {};
270
272
  let { redirectUri } = opts ?? {};
@@ -279,6 +281,22 @@ export class OpenID4VCIClientV1_0_13 {
279
281
  this._state.pkce.codeVerifier = opts.codeVerifier;
280
282
  }
281
283
  this.assertIssuerData();
284
+ const asOpts: AuthorizationServerOpts = { ...opts?.asOpts };
285
+ const kid = asOpts.clientOpts?.kid ?? this._state.kid ?? this._state.authorizationRequestOpts?.requestObjectOpts?.kid;
286
+ const clientAssertionType =
287
+ asOpts.clientOpts?.clientAssertionType ??
288
+ (kid && clientId && typeof asOpts.clientOpts?.signCallbacks === 'function'
289
+ ? 'urn:ietf:params:oauth:client-assertion-type:jwt-bearer'
290
+ : undefined);
291
+ if (clientId) {
292
+ asOpts.clientOpts = {
293
+ ...asOpts.clientOpts,
294
+ clientId,
295
+ ...(kid && { kid }),
296
+ ...(clientAssertionType && { clientAssertionType }),
297
+ signCallbacks: asOpts.clientOpts?.signCallbacks ?? this._state.authorizationRequestOpts?.requestObjectOpts?.signCallbacks,
298
+ };
299
+ }
282
300
 
283
301
  if (clientId) {
284
302
  this._state.clientId = clientId;
@@ -302,7 +320,7 @@ export class OpenID4VCIClientV1_0_13 {
302
320
  ...(!this._state.pkce.disabled && { codeVerifier: this._state.pkce.codeVerifier }),
303
321
  code,
304
322
  redirectUri,
305
- asOpts: { clientId: this.clientId },
323
+ asOpts,
306
324
  });
307
325
 
308
326
  if (response.errorBody) {
@@ -20,13 +20,8 @@ import * as jose from 'jose';
20
20
  // @ts-ignore
21
21
  import nock from 'nock';
22
22
 
23
- import {
24
- CredentialOfferClientV1_0_11,
25
- CredentialRequestClientBuilder,
26
- CredentialRequestClientBuilderV1_0_11,
27
- MetadataClientV1_0_11,
28
- ProofOfPossessionBuilder,
29
- } from '..';
23
+ import { CredentialOfferClient, MetadataClient, ProofOfPossessionBuilder } from '..';
24
+ import { CredentialRequestClientBuilder } from '../CredentialRequestClientBuilder';
30
25
 
31
26
  import { IDENTIPROOF_ISSUER_URL, IDENTIPROOF_OID4VCI_METADATA, INITIATION_TEST, WALT_OID4VCI_METADATA } from './MetadataMocks';
32
27
  import { getMockData } from './data/VciDataFixtures';
@@ -154,14 +149,14 @@ describe('Credential Request Client with Walt.id ', () => {
154
149
  nock.cleanAll();
155
150
  const WALT_IRR_URI =
156
151
  'openid-initiate-issuance://?issuer=https%3A%2F%2Fjff.walt.id%2Fissuer-api%2Foidc%2F&credential_type=OpenBadgeCredential&pre-authorized_code=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJhOTUyZjUxNi1jYWVmLTQ4YjMtODIxYy00OTRkYzgyNjljZjAiLCJwcmUtYXV0aG9yaXplZCI6dHJ1ZX0.YE5DlalcLC2ChGEg47CQDaN1gTxbaQqSclIVqsSAUHE&user_pin_required=false';
157
- const credentialOffer = await CredentialOfferClientV1_0_11.fromURI(WALT_IRR_URI);
152
+ const credentialOffer = await CredentialOfferClient.fromURI(WALT_IRR_URI);
158
153
 
159
154
  const request = credentialOffer.credential_offer;
160
- const metadata = await MetadataClientV1_0_11.retrieveAllMetadata(getIssuerFromCredentialOfferPayload(request) as string);
155
+ const metadata = await MetadataClient.retrieveAllMetadata(getIssuerFromCredentialOfferPayload(request) as string);
161
156
  expect(metadata.credential_endpoint).toEqual(WALT_OID4VCI_METADATA.credential_endpoint);
162
157
  expect(metadata.token_endpoint).toEqual(WALT_OID4VCI_METADATA.token_endpoint);
163
158
 
164
- const credReqClient = CredentialRequestClientBuilderV1_0_11.fromCredentialOffer({
159
+ const credReqClient = CredentialRequestClientBuilder.fromCredentialOffer({
165
160
  credentialOffer,
166
161
  metadata,
167
162
  }).build();
@@ -205,7 +200,7 @@ describe('Credential Request Client with different issuers ', () => {
205
200
  const IRR_URI =
206
201
  'openid-initiate-issuance://?issuer=https%3A%2F%2Fjff.walt.id%2Fissuer-api%2Fdefault%2Foidc%2F&credential_type=OpenBadgeCredential&pre-authorized_code=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIwMTc4OTNjYy04ZTY3LTQxNzItYWZlOS1lODcyYmYxNDBlNWMiLCJwcmUtYXV0aG9yaXplZCI6dHJ1ZX0.ODfq2AIhOcB61dAb3zMrXBJjPJaf53zkeHh_AssYyYA&user_pin_required=false';
207
202
  const credentialOffer = await (
208
- await CredentialRequestClientBuilderV1_0_11.fromURI({
203
+ await CredentialRequestClientBuilder.fromURI({
209
204
  uri: IRR_URI,
210
205
  metadata: getMockData('walt')?.metadata as unknown as EndpointMetadata,
211
206
  })
@@ -250,7 +245,7 @@ describe('Credential Request Client with different issuers ', () => {
250
245
  const IRR_URI =
251
246
  'openid-initiate-issuance://?issuer=https://launchpad.mattrlabs.com&credential_type=OpenBadgeCredential&pre-authorized_code=g0UCOj6RAN5AwHU6gczm_GzB4_lH6GW39Z0Dl2DOOiO';
252
247
  const credentialOffer = await (
253
- await CredentialRequestClientBuilderV1_0_11.fromURI({
248
+ await CredentialRequestClientBuilder.fromURI({
254
249
  uri: IRR_URI,
255
250
  metadata: getMockData('mattr')?.metadata as unknown as EndpointMetadata,
256
251
  })
@@ -273,7 +268,7 @@ describe('Credential Request Client with different issuers ', () => {
273
268
  const IRR_URI =
274
269
  'openid-initiate-issuance://?issuer=https://oidc4vc.diwala.io&credential_type=OpenBadgeCredential&pre-authorized_code=eyJhbGciOiJIUzI1NiJ9.eyJjcmVkZW50aWFsX3R5cGUiOiJPcGVuQmFkZ2VDcmVkZW50aWFsIiwiZXhwIjoxNjgxOTg0NDY3fQ.fEAHKz2nuWfiYHw406iNxr-81pWkNkbi31bWsYSf6Ng';
275
270
  const credentialOffer = await (
276
- await CredentialRequestClientBuilderV1_0_11.fromURI({
271
+ await CredentialRequestClientBuilder.fromURI({
277
272
  uri: IRR_URI,
278
273
  metadata: getMockData('diwala')?.metadata as unknown as EndpointMetadata,
279
274
  })
@@ -11,11 +11,13 @@ import {
11
11
  } from '@sphereon/oid4vci-common';
12
12
  import * as jose from 'jose';
13
13
 
14
- import { CredentialRequestClientBuilder, ProofOfPossessionBuilder } from '..';
14
+ import { CredentialRequestOpts, ProofOfPossessionBuilder } from '..';
15
+ import { CredentialRequestClientBuilder } from '../CredentialRequestClientBuilder';
15
16
 
16
17
  import { IDENTIPROOF_ISSUER_URL, IDENTIPROOF_OID4VCI_METADATA, INITIATION_TEST_URI, WALT_ISSUER_URL, WALT_OID4VCI_METADATA } from './MetadataMocks';
17
18
 
18
19
  const partialJWT = 'eyJhbGciOiJFUzI1NiJ9.eyJpc3MiOiJkaWQ6ZXhhbXBsZTplYmZlYjFmN';
20
+ const partialJWT_withoutDid = 'eyJhbGciOiJFUzI1NiJ9.eyJpc3MiOiJlYmZlYjFmNzEyZWJjNmYxYzI3N';
19
21
 
20
22
  /*const jwtv1_0_08: Jwt = {
21
23
  header: { alg: Alg.ES256, kid: 'did:example:ebfeb1f712ebc6f1c276e12ec21/keys/1', typ: 'jwt' },
@@ -27,8 +29,15 @@ const jwtv1_0_11: Jwt = {
27
29
  payload: { iss: 'sphereon:wallet', nonce: 'tZignsnFbp', jti: 'tZignsnFbp223', aud: IDENTIPROOF_ISSUER_URL },
28
30
  };
29
31
 
32
+ const jwtv1_0_13_withoutDid: Jwt = {
33
+ header: { alg: Alg.ES256, kid: 'ebfeb1f712ebc6f1c276e12ec21/keys/1', typ: 'openid4vci-proof+jwt' },
34
+ payload: { iss: 'sphereon:wallet', nonce: 'tZignsnFbp', jti: 'tZignsnFbp223', aud: IDENTIPROOF_ISSUER_URL },
35
+ };
36
+
30
37
  const kid = 'did:example:ebfeb1f712ebc6f1c276e12ec21/keys/1';
31
38
 
39
+ const kid_withoutDid = 'ebfeb1f712ebc6f1c276e12ec21/keys/1';
40
+
32
41
  let keypair: KeyPair;
33
42
 
34
43
  beforeAll(async () => {
@@ -81,7 +90,7 @@ describe('Credential Request Client Builder', () => {
81
90
  .build();
82
91
  expect(credReqClient.credentialRequestOpts.credentialEndpoint).toBe('https://oidc4vci.demo.spruceid.com/credential');
83
92
  expect(credReqClient.credentialRequestOpts.format).toBe('jwt_vc');
84
- expect(credReqClient.credentialRequestOpts.credentialIdentifier).toStrictEqual('credentialType');
93
+ expect((credReqClient.credentialRequestOpts as CredentialRequestOpts).credentialIdentifier).toStrictEqual('credentialType');
85
94
  expect(credReqClient.credentialRequestOpts.token).toBe('token');
86
95
  });
87
96
 
@@ -115,6 +124,35 @@ describe('Credential Request Client Builder', () => {
115
124
  }
116
125
  });
117
126
 
127
+ it('should build credential request correctly without did', async () => {
128
+ const credReqClient = (await CredentialRequestClientBuilder.fromURI({ uri: INITIATION_TEST_URI }))
129
+ .withCredentialEndpoint('https://oidc4vci.demo.spruceid.com/credential')
130
+ .withFormat('jwt_vc')
131
+ .withCredentialType('OpenBadgeCredential')
132
+ .build();
133
+ const proof: ProofOfPossession = await ProofOfPossessionBuilder.fromJwt({
134
+ jwt: jwtv1_0_13_withoutDid,
135
+ callbacks: {
136
+ signCallback: proofOfPossessionCallbackFunction,
137
+ verifyCallback: proofOfPossessionVerifierCallbackFunction,
138
+ },
139
+ version: OpenId4VCIVersion.VER_1_0_13,
140
+ })
141
+ .withClientId('sphereon:wallet')
142
+ .withKid(kid_withoutDid)
143
+ .build();
144
+ await proofOfPossessionVerifierCallbackFunction({ ...proof, kid: kid_withoutDid });
145
+ const credentialRequest: CredentialRequestV1_0_13 = await credReqClient.createCredentialRequest({
146
+ proofInput: proof,
147
+ credentialTypes: 'OpenBadgeCredential',
148
+ version: OpenId4VCIVersion.VER_1_0_13,
149
+ });
150
+ expect(credentialRequest.proof?.jwt).toContain(partialJWT_withoutDid);
151
+ if ('types' in credentialRequest) {
152
+ expect(credentialRequest.types).toStrictEqual(['OpenBadgeCredential']);
153
+ }
154
+ });
155
+
118
156
  it('should build correctly from metadata', async () => {
119
157
  const credReqClient = (
120
158
  await CredentialRequestClientBuilder.fromURI({
@@ -28,14 +28,22 @@ import {
28
28
  import { getMockData } from './data/VciDataFixtures';
29
29
 
30
30
  const partialJWT = 'eyJhbGciOiJFUzI1NiJ9.eyJpc3MiOiJkaWQ6ZXhhbXBsZTplYmZlYjFmN';
31
+ const partialJWT_withoutDid = 'eyJhbGciOiJFUzI1NiJ9.eyJpc3MiOiJlYmZlYjFmNzEyZWJjNmYxYzI3N';
31
32
 
32
33
  const jwt: Jwt = {
33
34
  header: { alg: Alg.ES256, kid: 'did:example:ebfeb1f712ebc6f1c276e12ec21/keys/1', typ: 'jwt' },
34
35
  payload: { iss: 'sphereon:wallet', nonce: 'tZignsnFbp', jti: 'tZignsnFbp223', aud: IDENTIPROOF_ISSUER_URL },
35
36
  };
36
37
 
38
+ const jwt_withoutDid: Jwt = {
39
+ header: { alg: Alg.ES256, kid: 'ebfeb1f712ebc6f1c276e12ec21/keys/1', typ: 'jwt' },
40
+ payload: { iss: 'sphereon:wallet', nonce: 'tZignsnFbp', jti: 'tZignsnFbp223', aud: IDENTIPROOF_ISSUER_URL },
41
+ };
42
+
37
43
  const kid = 'did:example:ebfeb1f712ebc6f1c276e12ec21/keys/1';
38
44
 
45
+ const kid_withoutDid = 'ebfeb1f712ebc6f1c276e12ec21/keys/1';
46
+
39
47
  let keypair: KeyPair;
40
48
 
41
49
  async function proofOfPossessionCallbackFunction(args: Jwt, kid?: string): Promise<string> {
@@ -102,6 +110,36 @@ describe('Credential Request Client ', () => {
102
110
  expect(result?.errorBody?.error).toBe('unsupported_format');
103
111
  });
104
112
 
113
+ it('should get a failed credential response with an unsupported format and without did', async function () {
114
+ const basePath = 'https://sphereonjunit2022101301.com/';
115
+ nock(basePath).post(/.*/).reply(500, {
116
+ error: 'unsupported_format',
117
+ error_description: 'This is a mock error message',
118
+ });
119
+
120
+ const credReqClient = CredentialRequestClientBuilderV1_0_11.fromCredentialOffer({ credentialOffer: INITIATION_TEST_V1_0_08 })
121
+ .withCredentialEndpoint(basePath + '/credential')
122
+ .withFormat('ldp_vc')
123
+ .withCredentialType('https://imsglobal.github.io/openbadges-specification/ob_v3p0.html#OpenBadgeCredential')
124
+ .build();
125
+ const proof: ProofOfPossession = await ProofOfPossessionBuilder.fromJwt({
126
+ jwt: jwt_withoutDid,
127
+ callbacks: {
128
+ signCallback: proofOfPossessionCallbackFunction,
129
+ },
130
+ version: OpenId4VCIVersion.VER_1_0_08,
131
+ })
132
+ // .withEndpointMetadata(metadata)
133
+ .withClientId('sphereon:wallet')
134
+ .withKid(kid_withoutDid)
135
+ .build();
136
+ expect(credReqClient.getCredentialEndpoint()).toEqual(basePath + '/credential');
137
+ const credentialRequest = await credReqClient.createCredentialRequest({ proofInput: proof, version: OpenId4VCIVersion.VER_1_0_08 });
138
+ expect(credentialRequest.proof?.jwt?.includes(partialJWT_withoutDid)).toBeTruthy();
139
+ const result = await credReqClient.acquireCredentialsUsingRequest(credentialRequest);
140
+ expect(result?.errorBody?.error).toBe('unsupported_format');
141
+ });
142
+
105
143
  it('should get success credential response', async function () {
106
144
  const mockedVC =
107
145
  'eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCJ9.eyJ2YyI6eyJAY29udGV4dCI6WyJodHRwczovL3d3dy53My5vcmcvMjAxOC9jcmVkZW50aWFscy92MSIsImh0dHBzOi8vd3d3LnczLm9yZy8yMDE4L2NyZWRlbnRpYWxzL2V4YW1wbGVzL3YxIl0sImlkIjoiaHR0cDovL2V4YW1wbGUuZWR1L2NyZWRlbnRpYWxzLzM3MzIiLCJ0eXBlIjpbIlZlcmlmaWFibGVDcmVkZW50aWFsIiwiVW5pdmVyc2l0eURlZ3JlZUNyZWRlbnRpYWwiXSwiaXNzdWVyIjoiaHR0cHM6Ly9leGFtcGxlLmVkdS9pc3N1ZXJzLzU2NTA0OSIsImlzc3VhbmNlRGF0ZSI6IjIwMTAtMDEtMDFUMDA6MDA6MDBaIiwiY3JlZGVudGlhbFN1YmplY3QiOnsiaWQiOiJkaWQ6ZXhhbXBsZTplYmZlYjFmNzEyZWJjNmYxYzI3NmUxMmVjMjEiLCJkZWdyZWUiOnsidHlwZSI6IkJhY2hlbG9yRGVncmVlIiwibmFtZSI6IkJhY2hlbG9yIG9mIFNjaWVuY2UgYW5kIEFydHMifX19LCJpc3MiOiJodHRwczovL2V4YW1wbGUuZWR1L2lzc3VlcnMvNTY1MDQ5IiwibmJmIjoxMjYyMzA0MDAwLCJqdGkiOiJodHRwOi8vZXhhbXBsZS5lZHUvY3JlZGVudGlhbHMvMzczMiIsInN1YiI6ImRpZDpleGFtcGxlOmViZmViMWY3MTJlYmM2ZjFjMjc2ZTEyZWMyMSJ9.z5vgMTK1nfizNCg5N-niCOL3WUIAL7nXy-nGhDZYO_-PNGeE-0djCpWAMH8fD8eWSID5PfkPBYkx_dfLJnQ7NA';
@@ -138,6 +176,42 @@ describe('Credential Request Client ', () => {
138
176
  expect(result?.successBody?.credential).toEqual(mockedVC);
139
177
  });
140
178
 
179
+ it('should get success credential response without did', async function () {
180
+ const mockedVC =
181
+ 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ2YyI6eyJAY29udGV4dCI6WyJodHRwczovL3d3dy53My5vcmcvMjAxOC9jcmVkZW50aWFscy92MSIsImh0dHBzOi8vd3d3LnczLm9yZy8yMDE4L2NyZWRlbnRpYWxzL2V4YW1wbGVzL3YxIl0sImlkIjoiaHR0cDovL2V4YW1wbGUuZWR1L2NyZWRlbnRpYWxzLzM3MzIiLCJ0eXBlIjpbIlZlcmlmaWFibGVDcmVkZW50aWFsIiwiVW5pdmVyc2l0eURlZ3JlZUNyZWRlbnRpYWwiXSwiaXNzdWVyIjoiaHR0cHM6Ly9leGFtcGxlLmVkdS9pc3N1ZXJzLzU2NTA0OSIsImlzc3VhbmNlRGF0ZSI6IjIwMTAtMDEtMDFUMDA6MDA6MDBaIiwiY3JlZGVudGlhbFN1YmplY3QiOnsiaWQiOiJlYmZlYjFmNzEyZWJjNmYxYzI3NmUxMmVjMjEiLCJkZWdyZWUiOnsidHlwZSI6IkJhY2hlbG9yRGVncmVlIiwibmFtZSI6IkJhY2hlbG9yIG9mIFNjaWVuY2UgYW5kIEFydHMifX19LCJpc3MiOiJodHRwczovL2V4YW1wbGUuZWR1L2lzc3VlcnMvNTY1MDQ5IiwibmJmIjoxMjYyMzA0MDAwLCJqdGkiOiJodHRwOi8vZXhhbXBsZS5lZHUvY3JlZGVudGlhbHMvMzczMiIsInN1YiI6ImViZmViMWY3MTJlYmM2ZjFjMjc2ZTEyZWMyMSIsImlhdCI6MTcxODM1NzcxOH0.7iiOTuIjQRyrIincYyDW6m0nBYmDoYfXcTYFrywsKEY';
182
+ nock('https://oidc4vci.demo.spruceid.com')
183
+ .post(/credential/)
184
+ .reply(200, {
185
+ format: 'jwt-vc',
186
+ credential: mockedVC,
187
+ });
188
+ const credReqClient = CredentialRequestClientBuilderV1_0_11.fromCredentialOfferRequest({ request: INITIATION_TEST })
189
+ .withCredentialEndpoint('https://oidc4vci.demo.spruceid.com/credential')
190
+ .withFormat('jwt_vc')
191
+ .withCredentialType('https://imsglobal.github.io/openbadges-specification/ob_v3p0.html#OpenBadgeCredential')
192
+ .build();
193
+ const proof: ProofOfPossession = await ProofOfPossessionBuilder.fromJwt({
194
+ jwt: jwt_withoutDid,
195
+ callbacks: {
196
+ signCallback: proofOfPossessionCallbackFunction,
197
+ },
198
+ version: OpenId4VCIVersion.VER_1_0_08,
199
+ })
200
+ // .withEndpointMetadata(metadata)
201
+ .withKid(kid_withoutDid)
202
+ .withClientId('sphereon:wallet')
203
+ .build();
204
+ const credentialRequest = await credReqClient.createCredentialRequest({
205
+ proofInput: proof,
206
+ format: 'jwt',
207
+ version: OpenId4VCIVersion.VER_1_0_08,
208
+ });
209
+ expect(credentialRequest.proof?.jwt?.includes(partialJWT_withoutDid)).toBeTruthy();
210
+ expect(credentialRequest.format).toEqual('jwt_vc');
211
+ const result = await credReqClient.acquireCredentialsUsingRequest(credentialRequest);
212
+ expect(result?.successBody?.credential).toEqual(mockedVC);
213
+ });
214
+
141
215
  it('should fail with invalid url', async () => {
142
216
  const credReqClient = CredentialRequestClientBuilderV1_0_11.fromCredentialOfferRequest({ request: INITIATION_TEST })
143
217
  .withCredentialEndpoint('httpsf://oidc4vci.demo.spruceid.com/credential')
@@ -159,6 +233,28 @@ describe('Credential Request Client ', () => {
159
233
  Error(URL_NOT_VALID),
160
234
  );
161
235
  });
236
+
237
+ it('should fail with invalid url without did', async () => {
238
+ const credReqClient = CredentialRequestClientBuilderV1_0_11.fromCredentialOfferRequest({ request: INITIATION_TEST })
239
+ .withCredentialEndpoint('httpsf://oidc4vci.demo.spruceid.com/credential')
240
+ .withFormat('jwt_vc')
241
+ .withCredentialType('https://imsglobal.github.io/openbadges-specification/ob_v3p0.html#OpenBadgeCredential')
242
+ .build();
243
+ const proof: ProofOfPossession = await ProofOfPossessionBuilder.fromJwt({
244
+ jwt: jwt_withoutDid,
245
+ callbacks: {
246
+ signCallback: proofOfPossessionCallbackFunction,
247
+ },
248
+ version: OpenId4VCIVersion.VER_1_0_08,
249
+ })
250
+ // .withEndpointMetadata(metadata)
251
+ .withKid(kid_withoutDid)
252
+ .withClientId('sphereon:wallet')
253
+ .build();
254
+ await expect(credReqClient.acquireCredentialsUsingRequest({ format: 'jwt_vc_json', types: ['random'], proof })).rejects.toThrow(
255
+ Error(URL_NOT_VALID),
256
+ );
257
+ });
162
258
  });
163
259
 
164
260
  describe('Credential Request Client with Walt.id ', () => {