@sphereon/oid4vci-client 0.16.1-next.4 → 0.16.1-next.402

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 (112) hide show
  1. package/README.md +0 -1
  2. package/dist/AccessTokenClient.d.ts.map +1 -1
  3. package/dist/AccessTokenClient.js +10 -9
  4. package/dist/AccessTokenClient.js.map +1 -1
  5. package/dist/AccessTokenClientV1_0_11.js +9 -8
  6. package/dist/AccessTokenClientV1_0_11.js.map +1 -1
  7. package/dist/AuthorizationCodeClient.d.ts +11 -1
  8. package/dist/AuthorizationCodeClient.d.ts.map +1 -1
  9. package/dist/AuthorizationCodeClient.js +66 -6
  10. package/dist/AuthorizationCodeClient.js.map +1 -1
  11. package/dist/AuthorizationCodeClientV1_0_11.js.map +1 -1
  12. package/dist/CredentialOfferClient.d.ts.map +1 -1
  13. package/dist/CredentialOfferClient.js +14 -15
  14. package/dist/CredentialOfferClient.js.map +1 -1
  15. package/dist/CredentialOfferClientV1_0_11.js +1 -1
  16. package/dist/CredentialOfferClientV1_0_11.js.map +1 -1
  17. package/dist/CredentialOfferClientV1_0_13.d.ts.map +1 -1
  18. package/dist/CredentialOfferClientV1_0_13.js +18 -17
  19. package/dist/CredentialOfferClientV1_0_13.js.map +1 -1
  20. package/dist/CredentialRequestClient.d.ts +37 -13
  21. package/dist/CredentialRequestClient.d.ts.map +1 -1
  22. package/dist/CredentialRequestClient.js +57 -14
  23. package/dist/CredentialRequestClient.js.map +1 -1
  24. package/dist/CredentialRequestClientBuilder.d.ts +1 -0
  25. package/dist/CredentialRequestClientBuilder.d.ts.map +1 -1
  26. package/dist/CredentialRequestClientBuilder.js +4 -0
  27. package/dist/CredentialRequestClientBuilder.js.map +1 -1
  28. package/dist/CredentialRequestClientBuilderV1_0_11.d.ts +2 -0
  29. package/dist/CredentialRequestClientBuilderV1_0_11.d.ts.map +1 -1
  30. package/dist/CredentialRequestClientBuilderV1_0_11.js +4 -0
  31. package/dist/CredentialRequestClientBuilderV1_0_11.js.map +1 -1
  32. package/dist/CredentialRequestClientBuilderV1_0_13.d.ts +2 -0
  33. package/dist/CredentialRequestClientBuilderV1_0_13.d.ts.map +1 -1
  34. package/dist/CredentialRequestClientBuilderV1_0_13.js +6 -1
  35. package/dist/CredentialRequestClientBuilderV1_0_13.js.map +1 -1
  36. package/dist/CredentialRequestClientV1_0_11.d.ts +4 -4
  37. package/dist/CredentialRequestClientV1_0_11.d.ts.map +1 -1
  38. package/dist/CredentialRequestClientV1_0_11.js +10 -0
  39. package/dist/CredentialRequestClientV1_0_11.js.map +1 -1
  40. package/dist/MetadataClient.d.ts +1 -0
  41. package/dist/MetadataClient.d.ts.map +1 -1
  42. package/dist/MetadataClient.js +13 -5
  43. package/dist/MetadataClient.js.map +1 -1
  44. package/dist/MetadataClientV1_0_11.d.ts.map +1 -1
  45. package/dist/MetadataClientV1_0_11.js +8 -1
  46. package/dist/MetadataClientV1_0_11.js.map +1 -1
  47. package/dist/MetadataClientV1_0_13.d.ts +1 -0
  48. package/dist/MetadataClientV1_0_13.d.ts.map +1 -1
  49. package/dist/MetadataClientV1_0_13.js +13 -5
  50. package/dist/MetadataClientV1_0_13.js.map +1 -1
  51. package/dist/OpenID4VCIClient.d.ts +15 -7
  52. package/dist/OpenID4VCIClient.d.ts.map +1 -1
  53. package/dist/OpenID4VCIClient.js +64 -22
  54. package/dist/OpenID4VCIClient.js.map +1 -1
  55. package/dist/OpenID4VCIClientV1_0_11.d.ts +9 -5
  56. package/dist/OpenID4VCIClientV1_0_11.d.ts.map +1 -1
  57. package/dist/OpenID4VCIClientV1_0_11.js +42 -17
  58. package/dist/OpenID4VCIClientV1_0_11.js.map +1 -1
  59. package/dist/OpenID4VCIClientV1_0_13.d.ts +29 -7
  60. package/dist/OpenID4VCIClientV1_0_13.d.ts.map +1 -1
  61. package/dist/OpenID4VCIClientV1_0_13.js +117 -47
  62. package/dist/OpenID4VCIClientV1_0_13.js.map +1 -1
  63. package/dist/ProofOfPossessionBuilder.d.ts +11 -11
  64. package/dist/ProofOfPossessionBuilder.d.ts.map +1 -1
  65. package/dist/ProofOfPossessionBuilder.js.map +1 -1
  66. package/dist/functions/AccessTokenUtil.js +2 -2
  67. package/dist/functions/AccessTokenUtil.js.map +1 -1
  68. package/dist/functions/CredentialOfferCommons.d.ts +19 -0
  69. package/dist/functions/CredentialOfferCommons.d.ts.map +1 -0
  70. package/dist/functions/CredentialOfferCommons.js +50 -0
  71. package/dist/functions/CredentialOfferCommons.js.map +1 -0
  72. package/dist/functions/index.d.ts +1 -0
  73. package/dist/functions/index.d.ts.map +1 -1
  74. package/dist/functions/index.js +1 -0
  75. package/dist/functions/index.js.map +1 -1
  76. package/dist/functions/notifications.d.ts +2 -2
  77. package/dist/functions/notifications.d.ts.map +1 -1
  78. package/dist/functions/notifications.js.map +1 -1
  79. package/lib/AccessTokenClient.ts +13 -12
  80. package/lib/AccessTokenClientV1_0_11.ts +11 -11
  81. package/lib/AuthorizationCodeClient.ts +92 -4
  82. package/lib/AuthorizationCodeClientV1_0_11.ts +2 -2
  83. package/lib/CredentialOfferClient.ts +12 -21
  84. package/lib/CredentialOfferClientV1_0_11.ts +1 -1
  85. package/lib/CredentialOfferClientV1_0_13.ts +17 -23
  86. package/lib/CredentialRequestClient.ts +98 -21
  87. package/lib/CredentialRequestClientBuilder.ts +4 -0
  88. package/lib/CredentialRequestClientBuilderV1_0_11.ts +6 -0
  89. package/lib/CredentialRequestClientBuilderV1_0_13.ts +10 -1
  90. package/lib/CredentialRequestClientV1_0_11.ts +14 -4
  91. package/lib/MetadataClient.ts +13 -2
  92. package/lib/MetadataClientV1_0_11.ts +10 -1
  93. package/lib/MetadataClientV1_0_13.ts +12 -2
  94. package/lib/OpenID4VCIClient.ts +80 -13
  95. package/lib/OpenID4VCIClientV1_0_11.ts +57 -12
  96. package/lib/OpenID4VCIClientV1_0_13.ts +160 -46
  97. package/lib/ProofOfPossessionBuilder.ts +13 -13
  98. package/lib/__tests__/AccessTokenClient.spec.ts +0 -2
  99. package/lib/__tests__/CredentialRequestClient.spec.ts +53 -0
  100. package/lib/__tests__/CredentialRequestClientBuilder.spec.ts +1 -1
  101. package/lib/__tests__/IT.spec.ts +1 -4
  102. package/lib/__tests__/MetadataClient.spec.ts +24 -2
  103. package/lib/__tests__/OpenID4VCIClient.spec.ts +44 -1
  104. package/lib/__tests__/OpenID4VCIClientV1_0_11.spec.ts +43 -0
  105. package/lib/__tests__/OpenID4VCIClientV1_0_13.spec.ts +43 -0
  106. package/lib/__tests__/SdJwt.spec.ts +16 -3
  107. package/lib/__tests__/SphereonE2E.spec.test.ts +1 -1
  108. package/lib/functions/AccessTokenUtil.ts +2 -2
  109. package/lib/functions/CredentialOfferCommons.ts +52 -0
  110. package/lib/functions/index.ts +1 -0
  111. package/lib/functions/notifications.ts +2 -2
  112. package/package.json +5 -6
@@ -3,6 +3,9 @@ import {
3
3
  AccessTokenRequestOpts,
4
4
  AccessTokenResponse,
5
5
  Alg,
6
+ AuthorizationChallengeCodeResponse,
7
+ AuthorizationChallengeErrorResponse,
8
+ AuthorizationChallengeRequestOpts,
6
9
  AuthorizationRequestOpts,
7
10
  AuthorizationResponse,
8
11
  AuthorizationServerOpts,
@@ -28,7 +31,7 @@ import {
28
31
  getTypesFromObject,
29
32
  KID_JWK_X5C_ERROR,
30
33
  NotificationRequest,
31
- NotificationResult,
34
+ NotificationResponseResult,
32
35
  OID4VCICredentialFormat,
33
36
  OpenId4VCIVersion,
34
37
  PKCEOpts,
@@ -40,7 +43,7 @@ import Debug from 'debug';
40
43
 
41
44
  import { AccessTokenClient } from './AccessTokenClient';
42
45
  import { AccessTokenClientV1_0_11 } from './AccessTokenClientV1_0_11';
43
- import { createAuthorizationRequestUrl } from './AuthorizationCodeClient';
46
+ import { acquireAuthorizationChallengeAuthCode, createAuthorizationRequestUrl } from './AuthorizationCodeClient';
44
47
  import { createAuthorizationRequestUrlV1_0_11 } from './AuthorizationCodeClientV1_0_11';
45
48
  import { CredentialOfferClient } from './CredentialOfferClient';
46
49
  import { CredentialRequestOpts } from './CredentialRequestClient';
@@ -89,7 +92,7 @@ export class OpenID4VCIClient {
89
92
  endpointMetadata?: EndpointMetadataResult;
90
93
  accessTokenResponse?: AccessTokenResponse;
91
94
  authorizationRequestOpts?: AuthorizationRequestOpts;
92
- authorizationCodeResponse?: AuthorizationResponse;
95
+ authorizationCodeResponse?: AuthorizationResponse | AuthorizationChallengeCodeResponse;
93
96
  authorizationURL?: string;
94
97
  }) {
95
98
  const issuer = credentialIssuer ?? (credentialOffer ? getIssuerFromCredentialOfferPayload(credentialOffer.credential_offer) : undefined);
@@ -130,6 +133,7 @@ export class OpenID4VCIClient {
130
133
  pkce,
131
134
  authorizationRequest,
132
135
  createAuthorizationRequestURL,
136
+ endpointMetadata,
133
137
  }: {
134
138
  credentialIssuer: string;
135
139
  kid?: string;
@@ -139,6 +143,7 @@ export class OpenID4VCIClient {
139
143
  createAuthorizationRequestURL?: boolean;
140
144
  authorizationRequest?: AuthorizationRequestOpts; // Can be provided here, or when manually calling createAuthorizationUrl
141
145
  pkce?: PKCEOpts;
146
+ endpointMetadata?: EndpointMetadataResult;
142
147
  }) {
143
148
  const client = new OpenID4VCIClient({
144
149
  kid,
@@ -147,6 +152,7 @@ export class OpenID4VCIClient {
147
152
  credentialIssuer,
148
153
  pkce,
149
154
  authorizationRequest,
155
+ endpointMetadata,
150
156
  });
151
157
  if (retrieveServerMetadata === undefined || retrieveServerMetadata) {
152
158
  await client.retrieveServerMetadata();
@@ -173,6 +179,7 @@ export class OpenID4VCIClient {
173
179
  createAuthorizationRequestURL,
174
180
  authorizationRequest,
175
181
  resolveOfferUri,
182
+ endpointMetadata,
176
183
  }: {
177
184
  uri: string;
178
185
  kid?: string;
@@ -183,6 +190,7 @@ export class OpenID4VCIClient {
183
190
  pkce?: PKCEOpts;
184
191
  clientId?: string;
185
192
  authorizationRequest?: AuthorizationRequestOpts; // Can be provided here, or when manually calling createAuthorizationUrl
193
+ endpointMetadata?: EndpointMetadataResult;
186
194
  }): Promise<OpenID4VCIClient> {
187
195
  const credentialOfferClient = await CredentialOfferClient.fromURI(uri, { resolve: resolveOfferUri });
188
196
  const client = new OpenID4VCIClient({
@@ -192,6 +200,7 @@ export class OpenID4VCIClient {
192
200
  clientId: clientId ?? authorizationRequest?.clientId ?? credentialOfferClient.clientId,
193
201
  pkce,
194
202
  authorizationRequest,
203
+ endpointMetadata,
195
204
  });
196
205
 
197
206
  if (retrieveServerMetadata === undefined || retrieveServerMetadata) {
@@ -270,21 +279,41 @@ export class OpenID4VCIClient {
270
279
  this._state.pkce = generateMissingPKCEOpts({ ...this._state.pkce, ...pkce });
271
280
  }
272
281
 
282
+ public async acquireAuthorizationChallengeCode(opts?: AuthorizationChallengeRequestOpts): Promise<AuthorizationChallengeCodeResponse> {
283
+ const response = await acquireAuthorizationChallengeAuthCode({
284
+ metadata: this.endpointMetadata,
285
+ credentialIssuer: this.getIssuer(),
286
+ clientId: this._state.clientId ?? this._state.authorizationRequestOpts?.clientId,
287
+ ...opts,
288
+ });
289
+
290
+ if (response.errorBody) {
291
+ debug(`Authorization code error:\r\n${JSON.stringify(response.errorBody)}`);
292
+ const error = response.errorBody as AuthorizationChallengeErrorResponse;
293
+ return Promise.reject(error);
294
+ } else if (!response.successBody) {
295
+ debug(`Authorization code error. No success body`);
296
+ return Promise.reject(
297
+ Error(
298
+ `Retrieving an authorization code token from ${this._state.endpointMetadata?.authorization_challenge_endpoint} for issuer ${this.getIssuer()} failed as there was no success response body`,
299
+ ),
300
+ );
301
+ }
302
+
303
+ return { ...response.successBody };
304
+ }
305
+
273
306
  public async acquireAccessToken(
274
307
  opts?: Omit<AccessTokenRequestOpts, 'credentialOffer' | 'credentialIssuer' | 'metadata' | 'additionalParams'> & {
275
308
  clientId?: string;
276
- authorizationResponse?: string | AuthorizationResponse; // Pass in an auth response, either as URI/redirect, or object
309
+ authorizationResponse?: string | AuthorizationResponse | AuthorizationChallengeCodeResponse; // Pass in an auth response, either as URI/redirect, or object
277
310
  additionalRequestParams?: Record<string, any>;
278
311
  },
279
- ): Promise<AccessTokenResponse & DPoPResponseParams> {
312
+ ): Promise<AccessTokenResponse & { params?: DPoPResponseParams }> {
280
313
  const { pin, clientId = this._state.clientId ?? this._state.authorizationRequestOpts?.clientId } = opts ?? {};
281
314
  let { redirectUri } = opts ?? {};
282
- if (opts?.authorizationResponse) {
283
- this._state.authorizationCodeResponse = { ...toAuthorizationResponsePayload(opts.authorizationResponse) };
284
- } else if (opts?.code) {
285
- this._state.authorizationCodeResponse = { code: opts.code };
286
- }
287
- const code = this._state.authorizationCodeResponse?.code;
315
+
316
+ const code = this.getAuthorizationCode(opts?.authorizationResponse, opts?.code);
288
317
 
289
318
  if (opts?.codeVerifier) {
290
319
  this._state.pkce.codeVerifier = opts.codeVerifier;
@@ -313,6 +342,10 @@ export class OpenID4VCIClient {
313
342
 
314
343
  if (clientId) {
315
344
  this._state.clientId = clientId;
345
+ if (!asOpts.clientOpts) {
346
+ asOpts.clientOpts = { clientId };
347
+ }
348
+ asOpts.clientOpts.clientId = clientId;
316
349
  }
317
350
  if (!this._state.accessTokenResponse) {
318
351
  const accessTokenClient = this.version() <= OpenId4VCIVersion.VER_1_0_12 ? new AccessTokenClientV1_0_11() : new AccessTokenClient();
@@ -377,7 +410,7 @@ export class OpenID4VCIClient {
377
410
  }: {
378
411
  credentialTypes: string | string[];
379
412
  context?: string[];
380
- proofCallbacks: ProofOfPossessionCallbacks<any>;
413
+ proofCallbacks: ProofOfPossessionCallbacks;
381
414
  format?: CredentialFormat | OID4VCICredentialFormat;
382
415
  kid?: string;
383
416
  jwk?: JWK;
@@ -422,6 +455,15 @@ export class OpenID4VCIClient {
422
455
  version: this.version(),
423
456
  });
424
457
  }
458
+ // 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
459
+ const issuerState =
460
+ this.issuerSupportedFlowTypes().includes(AuthzFlowType.AUTHORIZATION_CODE_FLOW) &&
461
+ this._state.authorizationCodeResponse &&
462
+ !this.accessTokenResponse?.c_nonce &&
463
+ this._state.credentialOffer?.issuerState
464
+ ? this._state.credentialOffer.issuerState
465
+ : undefined;
466
+ requestBuilder.withIssuerState(issuerState);
425
467
 
426
468
  requestBuilder.withTokenFromResponse(this.accessTokenResponse);
427
469
  requestBuilder.withDeferredCredentialAwait(deferredCredentialAwait ?? false, deferredCredentialIntervalInMS);
@@ -531,7 +573,7 @@ export class OpenID4VCIClient {
531
573
  credentialRequestOpts: Partial<CredentialRequestOpts>,
532
574
  request: NotificationRequest,
533
575
  accessToken?: string,
534
- ): Promise<NotificationResult> {
576
+ ): Promise<NotificationResponseResult> {
535
577
  return sendNotification(credentialRequestOpts, request, accessToken ?? this._state.accessToken ?? this._state.accessTokenResponse?.access_token);
536
578
  }
537
579
 
@@ -654,6 +696,15 @@ export class OpenID4VCIClient {
654
696
  return this.endpointMetadata ? this.endpointMetadata.credential_endpoint : `${this.getIssuer()}/credential`;
655
697
  }
656
698
 
699
+ public getAuthorizationChallengeEndpoint(): string | undefined {
700
+ this.assertIssuerData();
701
+ return this.endpointMetadata?.authorization_challenge_endpoint;
702
+ }
703
+
704
+ public hasAuthorizationChallengeEndpoint(): boolean {
705
+ return !!this.getAuthorizationChallengeEndpoint();
706
+ }
707
+
657
708
  public hasDeferredCredentialEndpoint(): boolean {
658
709
  return !!this.getAccessTokenEndpoint();
659
710
  }
@@ -727,4 +778,20 @@ export class OpenID4VCIClient {
727
778
  authorizationRequestOpts.clientId = clientId;
728
779
  return authorizationRequestOpts;
729
780
  }
781
+
782
+ private getAuthorizationCode = (
783
+ authorizationResponse?: string | AuthorizationResponse | AuthorizationChallengeCodeResponse,
784
+ code?: string,
785
+ ): string | undefined => {
786
+ if (authorizationResponse) {
787
+ this._state.authorizationCodeResponse = { ...toAuthorizationResponsePayload(authorizationResponse) };
788
+ } else if (code) {
789
+ this._state.authorizationCodeResponse = { code };
790
+ }
791
+
792
+ return (
793
+ (this._state.authorizationCodeResponse as AuthorizationResponse)?.code ??
794
+ (this._state.authorizationCodeResponse as AuthorizationChallengeCodeResponse)?.authorization_code
795
+ );
796
+ };
730
797
  }
@@ -3,6 +3,9 @@ import {
3
3
  AccessTokenRequestOpts,
4
4
  AccessTokenResponse,
5
5
  Alg,
6
+ AuthorizationChallengeCodeResponse,
7
+ AuthorizationChallengeErrorResponse,
8
+ AuthorizationChallengeRequestOpts,
6
9
  AuthorizationRequestOpts,
7
10
  AuthorizationResponse,
8
11
  AuthorizationServerOpts,
@@ -33,6 +36,7 @@ import { CredentialFormat } from '@sphereon/ssi-types';
33
36
  import Debug from 'debug';
34
37
 
35
38
  import { AccessTokenClientV1_0_11 } from './AccessTokenClientV1_0_11';
39
+ import { acquireAuthorizationChallengeAuthCode } from './AuthorizationCodeClient';
36
40
  import { createAuthorizationRequestUrlV1_0_11 } from './AuthorizationCodeClientV1_0_11';
37
41
  import { CredentialOfferClientV1_0_11 } from './CredentialOfferClientV1_0_11';
38
42
  import { CredentialRequestClientBuilderV1_0_11 } from './CredentialRequestClientBuilderV1_0_11';
@@ -53,7 +57,7 @@ export interface OpenID4VCIClientStateV1_0_11 {
53
57
  accessTokenResponse?: AccessTokenResponse;
54
58
  dpopResponseParams?: DPoPResponseParams;
55
59
  authorizationRequestOpts?: AuthorizationRequestOpts;
56
- authorizationCodeResponse?: AuthorizationResponse;
60
+ authorizationCodeResponse?: AuthorizationResponse | AuthorizationChallengeCodeResponse;
57
61
  pkce: PKCEOpts;
58
62
  accessToken?: string;
59
63
  authorizationURL?: string;
@@ -88,7 +92,7 @@ export class OpenID4VCIClientV1_0_11 {
88
92
  endpointMetadata?: EndpointMetadataResultV1_0_11;
89
93
  accessTokenResponse?: AccessTokenResponse;
90
94
  authorizationRequestOpts?: AuthorizationRequestOpts;
91
- authorizationCodeResponse?: AuthorizationResponse;
95
+ authorizationCodeResponse?: AuthorizationResponse | AuthorizationChallengeCodeResponse;
92
96
  authorizationURL?: string;
93
97
  }) {
94
98
  const issuer = credentialIssuer ?? (credentialOffer ? getIssuerFromCredentialOfferPayload(credentialOffer.credential_offer) : undefined);
@@ -256,29 +260,54 @@ export class OpenID4VCIClientV1_0_11 {
256
260
  this._state.pkce = generateMissingPKCEOpts({ ...this._state.pkce, ...pkce });
257
261
  }
258
262
 
263
+ public async acquireAuthorizationChallengeCode(opts?: AuthorizationChallengeRequestOpts): Promise<AuthorizationChallengeCodeResponse> {
264
+ const response = await acquireAuthorizationChallengeAuthCode({
265
+ metadata: this.endpointMetadata,
266
+ credentialIssuer: this.getIssuer(),
267
+ clientId: this._state.clientId ?? this._state.authorizationRequestOpts?.clientId,
268
+ ...opts,
269
+ });
270
+
271
+ if (response.errorBody) {
272
+ debug(`Authorization code error:\r\n${JSON.stringify(response.errorBody)}`);
273
+ const error = response.errorBody as AuthorizationChallengeErrorResponse;
274
+ return Promise.reject(error);
275
+ } else if (!response.successBody) {
276
+ debug(`Authorization code error. No success body`);
277
+ return Promise.reject(
278
+ Error(
279
+ `Retrieving an authorization code token from ${this._state.endpointMetadata?.authorization_challenge_endpoint} for issuer ${this.getIssuer()} failed as there was no success response body`,
280
+ ),
281
+ );
282
+ }
283
+
284
+ return { ...response.successBody };
285
+ }
286
+
259
287
  public async acquireAccessToken(
260
288
  opts?: Omit<AccessTokenRequestOpts, 'credentialOffer' | 'credentialIssuer' | 'metadata' | 'additionalParams'> & {
261
289
  clientId?: string;
262
- authorizationResponse?: string | AuthorizationResponse; // Pass in an auth response, either as URI/redirect, or object
290
+ authorizationResponse?: string | AuthorizationResponse | AuthorizationChallengeCodeResponse; // Pass in an auth response, either as URI/redirect, or object
263
291
  additionalRequestParams?: Record<string, any>;
264
292
  },
265
- ): Promise<AccessTokenResponse> {
293
+ ): Promise<AccessTokenResponse & { params?: DPoPResponseParams }> {
266
294
  const { pin, clientId = this._state.clientId ?? this._state.authorizationRequestOpts?.clientId } = opts ?? {};
267
295
  let { redirectUri } = opts ?? {};
268
- if (opts?.authorizationResponse) {
269
- this._state.authorizationCodeResponse = { ...toAuthorizationResponsePayload(opts.authorizationResponse) };
270
- } else if (opts?.code) {
271
- this._state.authorizationCodeResponse = { code: opts.code };
272
- }
273
- const code = this._state.authorizationCodeResponse?.code;
296
+
297
+ const code = this.getAuthorizationCode(opts?.authorizationResponse, opts?.code);
274
298
 
275
299
  if (opts?.codeVerifier) {
276
300
  this._state.pkce.codeVerifier = opts.codeVerifier;
277
301
  }
278
302
  this.assertIssuerData();
279
303
 
304
+ const asOpts: AuthorizationServerOpts = { ...opts?.asOpts };
280
305
  if (clientId) {
281
306
  this._state.clientId = clientId;
307
+ if (!asOpts.clientOpts) {
308
+ asOpts.clientOpts = { clientId };
309
+ }
310
+ asOpts.clientOpts.clientId = clientId;
282
311
  }
283
312
  if (!this._state.accessTokenResponse) {
284
313
  const accessTokenClient = new AccessTokenClientV1_0_11();
@@ -291,7 +320,7 @@ export class OpenID4VCIClientV1_0_11 {
291
320
  if (this._state.authorizationRequestOpts?.redirectUri && !redirectUri) {
292
321
  redirectUri = this._state.authorizationRequestOpts.redirectUri;
293
322
  }
294
- const asOpts: AuthorizationServerOpts = { ...opts?.asOpts };
323
+
295
324
  const kid = asOpts.clientOpts?.kid ?? this._state.kid ?? this._state.authorizationRequestOpts?.requestObjectOpts?.kid;
296
325
  const clientAssertionType =
297
326
  asOpts.clientOpts?.clientAssertionType ??
@@ -362,7 +391,7 @@ export class OpenID4VCIClientV1_0_11 {
362
391
  }: {
363
392
  credentialTypes: string | string[];
364
393
  context?: string[];
365
- proofCallbacks: ProofOfPossessionCallbacks<any>;
394
+ proofCallbacks: ProofOfPossessionCallbacks;
366
395
  format?: CredentialFormat | OID4VCICredentialFormat;
367
396
  kid?: string;
368
397
  jwk?: JWK;
@@ -672,4 +701,20 @@ export class OpenID4VCIClientV1_0_11 {
672
701
  authorizationRequestOpts.clientId = clientId;
673
702
  return authorizationRequestOpts;
674
703
  }
704
+
705
+ private getAuthorizationCode = (
706
+ authorizationResponse?: string | AuthorizationResponse | AuthorizationChallengeCodeResponse,
707
+ code?: string,
708
+ ): string | undefined => {
709
+ if (authorizationResponse) {
710
+ this._state.authorizationCodeResponse = { ...toAuthorizationResponsePayload(authorizationResponse) };
711
+ } else if (code) {
712
+ this._state.authorizationCodeResponse = { code };
713
+ }
714
+
715
+ return (
716
+ (this._state.authorizationCodeResponse as AuthorizationResponse)?.code ??
717
+ (this._state.authorizationCodeResponse as AuthorizationChallengeCodeResponse)?.authorization_code
718
+ );
719
+ };
675
720
  }
@@ -3,6 +3,9 @@ import {
3
3
  AccessTokenRequestOpts,
4
4
  AccessTokenResponse,
5
5
  Alg,
6
+ AuthorizationChallengeCodeResponse,
7
+ AuthorizationChallengeErrorResponse,
8
+ AuthorizationChallengeRequestOpts,
6
9
  AuthorizationRequestOpts,
7
10
  AuthorizationResponse,
8
11
  AuthorizationServerOpts,
@@ -22,7 +25,7 @@ import {
22
25
  getTypesFromCredentialSupported,
23
26
  KID_JWK_X5C_ERROR,
24
27
  NotificationRequest,
25
- NotificationResult,
28
+ NotificationResponseResult,
26
29
  OID4VCICredentialFormat,
27
30
  OpenId4VCIVersion,
28
31
  PKCEOpts,
@@ -33,10 +36,10 @@ import { CredentialFormat } from '@sphereon/ssi-types';
33
36
  import Debug from 'debug';
34
37
 
35
38
  import { AccessTokenClient } from './AccessTokenClient';
36
- import { createAuthorizationRequestUrl } from './AuthorizationCodeClient';
39
+ import { acquireAuthorizationChallengeAuthCode, createAuthorizationRequestUrl } from './AuthorizationCodeClient';
37
40
  import { CredentialOfferClient } from './CredentialOfferClient';
38
41
  import { CredentialRequestOpts } from './CredentialRequestClient';
39
- import { CredentialRequestClientBuilder } from './CredentialRequestClientBuilder';
42
+ import { CredentialRequestClientBuilderV1_0_13 } from './CredentialRequestClientBuilderV1_0_13';
40
43
  import { MetadataClientV1_0_13 } from './MetadataClientV1_0_13';
41
44
  import { ProofOfPossessionBuilder } from './ProofOfPossessionBuilder';
42
45
  import { generateMissingPKCEOpts, sendNotification } from './functions';
@@ -54,10 +57,11 @@ export interface OpenID4VCIClientStateV1_0_13 {
54
57
  accessTokenResponse?: AccessTokenResponse;
55
58
  dpopResponseParams?: DPoPResponseParams;
56
59
  authorizationRequestOpts?: AuthorizationRequestOpts;
57
- authorizationCodeResponse?: AuthorizationResponse;
60
+ authorizationCodeResponse?: AuthorizationResponse | AuthorizationChallengeCodeResponse;
58
61
  pkce: PKCEOpts;
59
62
  accessToken?: string;
60
63
  authorizationURL?: string;
64
+ sendIssuerStateIfNoNonce?: boolean;
61
65
  }
62
66
 
63
67
  export class OpenID4VCIClientV1_0_13 {
@@ -91,7 +95,7 @@ export class OpenID4VCIClientV1_0_13 {
91
95
  endpointMetadata?: EndpointMetadataResultV1_0_13;
92
96
  accessTokenResponse?: AccessTokenResponse;
93
97
  authorizationRequestOpts?: AuthorizationRequestOpts;
94
- authorizationCodeResponse?: AuthorizationResponse;
98
+ authorizationCodeResponse?: AuthorizationResponse | AuthorizationChallengeCodeResponse;
95
99
  authorizationURL?: string;
96
100
  }) {
97
101
  const issuer = credentialIssuer ?? (credentialOffer ? getIssuerFromCredentialOfferPayload(credentialOffer.credential_offer) : undefined);
@@ -261,21 +265,41 @@ export class OpenID4VCIClientV1_0_13 {
261
265
  this._state.pkce = generateMissingPKCEOpts({ ...this._state.pkce, ...pkce });
262
266
  }
263
267
 
268
+ public async acquireAuthorizationChallengeCode(opts?: AuthorizationChallengeRequestOpts): Promise<AuthorizationChallengeCodeResponse> {
269
+ const response = await acquireAuthorizationChallengeAuthCode({
270
+ metadata: this.endpointMetadata,
271
+ credentialIssuer: this.getIssuer(),
272
+ clientId: this._state.clientId ?? this._state.authorizationRequestOpts?.clientId,
273
+ ...opts,
274
+ });
275
+
276
+ if (response.errorBody) {
277
+ debug(`Authorization code error:\r\n${JSON.stringify(response.errorBody)}`);
278
+ const error = response.errorBody as AuthorizationChallengeErrorResponse;
279
+ return Promise.reject(error);
280
+ } else if (!response.successBody) {
281
+ debug(`Authorization code error. No success body`);
282
+ return Promise.reject(
283
+ Error(
284
+ `Retrieving an authorization code token from ${this._state.endpointMetadata?.authorization_challenge_endpoint} for issuer ${this.getIssuer()} failed as there was no success response body`,
285
+ ),
286
+ );
287
+ }
288
+
289
+ return { ...response.successBody };
290
+ }
291
+
264
292
  public async acquireAccessToken(
265
293
  opts?: Omit<AccessTokenRequestOpts, 'credentialOffer' | 'credentialIssuer' | 'metadata' | 'additionalParams'> & {
266
294
  clientId?: string;
267
- authorizationResponse?: string | AuthorizationResponse; // Pass in an auth response, either as URI/redirect, or object
295
+ authorizationResponse?: string | AuthorizationResponse | AuthorizationChallengeCodeResponse; // Pass in an auth response, either as URI/redirect, or object
268
296
  additionalRequestParams?: Record<string, any>;
269
297
  },
270
- ): Promise<AccessTokenResponse> {
298
+ ): Promise<AccessTokenResponse & { params?: DPoPResponseParams }> {
271
299
  const { pin, clientId = this._state.clientId ?? this._state.authorizationRequestOpts?.clientId } = opts ?? {};
272
300
  let { redirectUri } = opts ?? {};
273
- if (opts?.authorizationResponse) {
274
- this._state.authorizationCodeResponse = { ...toAuthorizationResponsePayload(opts.authorizationResponse) };
275
- } else if (opts?.code) {
276
- this._state.authorizationCodeResponse = { code: opts.code };
277
- }
278
- const code = this._state.authorizationCodeResponse?.code;
301
+
302
+ const code = this.getAuthorizationCode(opts?.authorizationResponse, opts?.code);
279
303
 
280
304
  if (opts?.codeVerifier) {
281
305
  this._state.pkce.codeVerifier = opts.codeVerifier;
@@ -303,6 +327,10 @@ export class OpenID4VCIClientV1_0_13 {
303
327
 
304
328
  if (clientId) {
305
329
  this._state.clientId = clientId;
330
+ if (!asOpts.clientOpts) {
331
+ asOpts.clientOpts = { clientId };
332
+ }
333
+ asOpts.clientOpts.clientId = clientId;
306
334
  }
307
335
  if (!this._state.accessTokenResponse) {
308
336
  const accessTokenClient = new AccessTokenClient();
@@ -351,7 +379,41 @@ export class OpenID4VCIClientV1_0_13 {
351
379
  return { ...this.accessTokenResponse, ...(this.dpopResponseParams && { params: this.dpopResponseParams }) };
352
380
  }
353
381
 
354
- public async acquireCredentials({
382
+ public async acquireCredentialsWithoutProof(args: {
383
+ credentialIdentifier?: string;
384
+ credentialTypes?: string | string[];
385
+ context?: string[];
386
+ format?: CredentialFormat | OID4VCICredentialFormat;
387
+ kid?: string;
388
+ jwk?: JWK;
389
+ alg?: Alg | string;
390
+ jti?: string;
391
+ deferredCredentialAwait?: boolean;
392
+ deferredCredentialIntervalInMS?: number;
393
+ experimentalHolderIssuanceSupported?: boolean;
394
+ createDPoPOpts?: CreateDPoPClientOpts;
395
+ }): Promise<CredentialResponse & { access_token: string }> {
396
+ return await this.acquireCredentialsImpl(args);
397
+ }
398
+ public async acquireCredentials(args: {
399
+ credentialIdentifier?: string;
400
+ credentialTypes?: string | string[];
401
+ context?: string[];
402
+ proofCallbacks: ProofOfPossessionCallbacks;
403
+ format?: CredentialFormat | OID4VCICredentialFormat;
404
+ kid?: string;
405
+ jwk?: JWK;
406
+ alg?: Alg | string;
407
+ jti?: string;
408
+ deferredCredentialAwait?: boolean;
409
+ deferredCredentialIntervalInMS?: number;
410
+ experimentalHolderIssuanceSupported?: boolean;
411
+ createDPoPOpts?: CreateDPoPClientOpts;
412
+ }): Promise<CredentialResponse & { access_token: string }> {
413
+ return await this.acquireCredentialsImpl(args);
414
+ }
415
+
416
+ private async acquireCredentialsImpl({
355
417
  credentialIdentifier,
356
418
  credentialTypes,
357
419
  context,
@@ -368,7 +430,7 @@ export class OpenID4VCIClientV1_0_13 {
368
430
  credentialIdentifier?: string;
369
431
  credentialTypes?: string | string[];
370
432
  context?: string[];
371
- proofCallbacks: ProofOfPossessionCallbacks<any>;
433
+ proofCallbacks?: ProofOfPossessionCallbacks;
372
434
  format?: CredentialFormat | OID4VCICredentialFormat;
373
435
  kid?: string;
374
436
  jwk?: JWK;
@@ -388,17 +450,25 @@ export class OpenID4VCIClientV1_0_13 {
388
450
  if (kid) this._state.kid = kid;
389
451
 
390
452
  const requestBuilder = this.credentialOffer
391
- ? CredentialRequestClientBuilder.fromCredentialOffer({
453
+ ? CredentialRequestClientBuilderV1_0_13.fromCredentialOffer({
392
454
  credentialOffer: this.credentialOffer,
393
455
  metadata: this.endpointMetadata,
394
456
  })
395
- : CredentialRequestClientBuilder.fromCredentialIssuer({
457
+ : CredentialRequestClientBuilderV1_0_13.fromCredentialIssuer({
396
458
  credentialIssuer: this.getIssuer(),
397
459
  credentialIdentifier: credentialIdentifier,
398
460
  metadata: this.endpointMetadata,
399
461
  version: this.version(),
400
462
  });
401
-
463
+ // 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
464
+ const issuerState =
465
+ this.issuerSupportedFlowTypes().includes(AuthzFlowType.AUTHORIZATION_CODE_FLOW) &&
466
+ this._state.authorizationCodeResponse &&
467
+ !this.accessTokenResponse?.c_nonce &&
468
+ this._state.credentialOffer?.issuerState
469
+ ? this._state.credentialOffer.issuerState
470
+ : undefined;
471
+ requestBuilder.withIssuerState(issuerState);
402
472
  requestBuilder.withTokenFromResponse(this.accessTokenResponse);
403
473
  requestBuilder.withDeferredCredentialAwait(deferredCredentialAwait ?? false, deferredCredentialIntervalInMS);
404
474
  let subjectIssuance: ExperimentalSubjectIssuance | undefined;
@@ -413,7 +483,7 @@ export class OpenID4VCIClientV1_0_13 {
413
483
  );
414
484
  }
415
485
  const credentialsSupported = metadata.credential_configurations_supported;
416
- if (!metadata.credential_configurations_supported || !credentialsSupported[credentialIdentifier]) {
486
+ if (!credentialsSupported || !credentialsSupported[credentialIdentifier]) {
417
487
  throw new Error(`Credential type ${credentialIdentifier} is not supported by issuer ${this.getIssuer()}`);
418
488
  }
419
489
  } else if (!types) {
@@ -438,9 +508,19 @@ export class OpenID4VCIClientV1_0_13 {
438
508
  console.log(`Not all credential types ${JSON.stringify(credentialTypes)} are present in metadata for ${this.getIssuer()}`);
439
509
  // throw Error(`Not all credential types ${JSON.stringify(credentialTypes)} are supported by issuer ${this.getIssuer()}`);
440
510
  }
441
- } else if (metadata.credential_configurations_supported && !Array.isArray(metadata.credential_configurations_supported)) {
442
- const credentialsSupported = metadata.credential_configurations_supported;
443
- if (types.some((type) => !metadata.credential_configurations_supported || !credentialsSupported[type])) {
511
+ } else if (metadata.credential_configurations_supported && typeof metadata.credential_configurations_supported === 'object') {
512
+ let typeSupported = false;
513
+ Object.values(metadata.credential_configurations_supported).forEach((supportedCredential) => {
514
+ const subTypes = getTypesFromCredentialSupported(supportedCredential);
515
+ if (
516
+ subTypes.every((t, i) => types[i] === t) ||
517
+ (types.length === 1 && (types[0] === supportedCredential.id || subTypes.includes(types[0])))
518
+ ) {
519
+ typeSupported = true;
520
+ }
521
+ });
522
+
523
+ if (!typeSupported) {
444
524
  throw Error(`Not all credential types ${JSON.stringify(credentialTypes)} are supported by issuer ${this.getIssuer()}`);
445
525
  }
446
526
  }
@@ -451,32 +531,50 @@ export class OpenID4VCIClientV1_0_13 {
451
531
  }
452
532
 
453
533
  const credentialRequestClient = requestBuilder.build();
454
- const proofBuilder = ProofOfPossessionBuilder.fromAccessTokenResponse({
455
- accessTokenResponse: this.accessTokenResponse,
456
- callbacks: proofCallbacks,
457
- version: this.version(),
458
- })
459
- .withIssuer(this.getIssuer())
460
- .withAlg(this.alg);
461
534
 
462
- if (this._state.jwk) {
463
- proofBuilder.withJWK(this._state.jwk);
464
- }
465
- if (this._state.kid) {
466
- proofBuilder.withKid(this._state.kid);
467
- }
535
+ let proofBuilder: ProofOfPossessionBuilder<any> | undefined;
536
+ if (proofCallbacks) {
537
+ proofBuilder = ProofOfPossessionBuilder.fromAccessTokenResponse({
538
+ accessTokenResponse: this.accessTokenResponse,
539
+ callbacks: proofCallbacks,
540
+ version: this.version(),
541
+ })
542
+ .withIssuer(this.getIssuer())
543
+ .withAlg(this.alg);
468
544
 
469
- if (this.clientId) {
470
- proofBuilder.withClientId(this.clientId);
471
- }
472
- if (jti) {
473
- proofBuilder.withJti(jti);
545
+ if (this._state.jwk) {
546
+ proofBuilder.withJWK(this._state.jwk);
547
+ }
548
+ if (this._state.kid) {
549
+ proofBuilder.withKid(this._state.kid);
550
+ }
551
+
552
+ if (this.clientId) {
553
+ proofBuilder.withClientId(this.clientId);
554
+ }
555
+ if (jti) {
556
+ proofBuilder.withJti(jti);
557
+ }
474
558
  }
475
- const response = await credentialRequestClient.acquireCredentialsUsingProof({
476
- proofInput: proofBuilder,
477
- ...(credentialIdentifier ? { credentialIdentifier, subjectIssuance } : { format, context, credentialTypes, subjectIssuance }),
478
- createDPoPOpts,
479
- });
559
+ const request = proofBuilder
560
+ ? await credentialRequestClient.createCredentialRequest({
561
+ proofInput: proofBuilder,
562
+ credentialTypes,
563
+ context,
564
+ format,
565
+ version: this.version(),
566
+ credentialIdentifier,
567
+ subjectIssuance,
568
+ })
569
+ : await credentialRequestClient.createCredentialRequestWithoutProof({
570
+ credentialTypes,
571
+ context,
572
+ format,
573
+ version: this.version(),
574
+ credentialIdentifier,
575
+ subjectIssuance,
576
+ });
577
+ const response = await credentialRequestClient.acquireCredentialsUsingRequest(request, createDPoPOpts);
480
578
  this._state.dpopResponseParams = response.params;
481
579
  if (response.errorBody) {
482
580
  debug(`Credential request error:\r\n${JSON.stringify(response.errorBody)}`);
@@ -515,7 +613,7 @@ export class OpenID4VCIClientV1_0_13 {
515
613
  credentialRequestOpts: Partial<CredentialRequestOpts>,
516
614
  request: NotificationRequest,
517
615
  accessToken?: string,
518
- ): Promise<NotificationResult> {
616
+ ): Promise<NotificationResponseResult> {
519
617
  return sendNotification(credentialRequestOpts, request, accessToken ?? this._state.accessToken ?? this._state.accessTokenResponse?.access_token);
520
618
  }
521
619
 
@@ -711,4 +809,20 @@ export class OpenID4VCIClientV1_0_13 {
711
809
  authorizationRequestOpts.clientId = clientId;
712
810
  return authorizationRequestOpts;
713
811
  }
812
+
813
+ private getAuthorizationCode = (
814
+ authorizationResponse?: string | AuthorizationResponse | AuthorizationChallengeCodeResponse,
815
+ code?: string,
816
+ ): string | undefined => {
817
+ if (authorizationResponse) {
818
+ this._state.authorizationCodeResponse = { ...toAuthorizationResponsePayload(authorizationResponse) };
819
+ } else if (code) {
820
+ this._state.authorizationCodeResponse = { code };
821
+ }
822
+
823
+ return (
824
+ (this._state.authorizationCodeResponse as AuthorizationResponse)?.code ??
825
+ (this._state.authorizationCodeResponse as AuthorizationChallengeCodeResponse)?.authorization_code
826
+ );
827
+ };
714
828
  }