@sphereon/oid4vci-client 0.15.1 → 0.15.2-next.38

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 (61) hide show
  1. package/dist/AccessTokenClient.d.ts +7 -5
  2. package/dist/AccessTokenClient.d.ts.map +1 -1
  3. package/dist/AccessTokenClient.js +26 -5
  4. package/dist/AccessTokenClient.js.map +1 -1
  5. package/dist/AccessTokenClientV1_0_11.d.ts +7 -5
  6. package/dist/AccessTokenClientV1_0_11.d.ts.map +1 -1
  7. package/dist/AccessTokenClientV1_0_11.js +25 -5
  8. package/dist/AccessTokenClientV1_0_11.js.map +1 -1
  9. package/dist/AuthorizationCodeClient.d.ts.map +1 -1
  10. package/dist/AuthorizationCodeClient.js +11 -14
  11. package/dist/AuthorizationCodeClient.js.map +1 -1
  12. package/dist/AuthorizationCodeClientV1_0_11.js +1 -1
  13. package/dist/AuthorizationCodeClientV1_0_11.js.map +1 -1
  14. package/dist/CredentialRequestClient.d.ts +5 -3
  15. package/dist/CredentialRequestClient.d.ts.map +1 -1
  16. package/dist/CredentialRequestClient.js +22 -4
  17. package/dist/CredentialRequestClient.js.map +1 -1
  18. package/dist/CredentialRequestClientV1_0_11.d.ts +5 -3
  19. package/dist/CredentialRequestClientV1_0_11.d.ts.map +1 -1
  20. package/dist/CredentialRequestClientV1_0_11.js +22 -4
  21. package/dist/CredentialRequestClientV1_0_11.js.map +1 -1
  22. package/dist/OpenID4VCIClient.d.ts +2 -1
  23. package/dist/OpenID4VCIClient.d.ts.map +1 -1
  24. package/dist/OpenID4VCIClient.js.map +1 -1
  25. package/dist/OpenID4VCIClientV1_0_11.d.ts +2 -1
  26. package/dist/OpenID4VCIClientV1_0_11.d.ts.map +1 -1
  27. package/dist/OpenID4VCIClientV1_0_11.js.map +1 -1
  28. package/dist/OpenID4VCIClientV1_0_13.d.ts +2 -1
  29. package/dist/OpenID4VCIClientV1_0_13.d.ts.map +1 -1
  30. package/dist/OpenID4VCIClientV1_0_13.js.map +1 -1
  31. package/dist/ProofOfPossessionBuilder.d.ts +2 -1
  32. package/dist/ProofOfPossessionBuilder.d.ts.map +1 -1
  33. package/dist/ProofOfPossessionBuilder.js.map +1 -1
  34. package/dist/functions/AccessTokenUtil.d.ts.map +1 -1
  35. package/dist/functions/AccessTokenUtil.js +2 -2
  36. package/dist/functions/AccessTokenUtil.js.map +1 -1
  37. package/dist/functions/dpopUtil.d.ts +10 -0
  38. package/dist/functions/dpopUtil.d.ts.map +1 -0
  39. package/dist/functions/dpopUtil.js +30 -0
  40. package/dist/functions/dpopUtil.js.map +1 -0
  41. package/dist/functions/notifications.d.ts.map +1 -1
  42. package/dist/functions/notifications.js +3 -3
  43. package/dist/functions/notifications.js.map +1 -1
  44. package/lib/AccessTokenClient.ts +44 -7
  45. package/lib/AccessTokenClientV1_0_11.ts +43 -7
  46. package/lib/AuthorizationCodeClient.ts +11 -13
  47. package/lib/AuthorizationCodeClientV1_0_11.ts +1 -1
  48. package/lib/CredentialRequestClient.ts +38 -5
  49. package/lib/CredentialRequestClientV1_0_11.ts +38 -5
  50. package/lib/OpenID4VCIClient.ts +2 -2
  51. package/lib/OpenID4VCIClientV1_0_11.ts +1 -1
  52. package/lib/OpenID4VCIClientV1_0_13.ts +1 -1
  53. package/lib/ProofOfPossessionBuilder.ts +1 -1
  54. package/lib/__tests__/AccessTokenClient.spec.ts +4 -11
  55. package/lib/__tests__/OpenID4VCIClient.spec.ts +2 -23
  56. package/lib/__tests__/OpenID4VCIClientV1_0_13.spec.ts +2 -23
  57. package/lib/__tests__/SphereonE2E.spec.test.ts +3 -3
  58. package/lib/functions/AccessTokenUtil.ts +2 -2
  59. package/lib/functions/dpopUtil.ts +35 -0
  60. package/lib/functions/notifications.ts +2 -4
  61. package/package.json +4 -3
@@ -59,27 +59,6 @@ describe('OpenID4VCIClient should', () => {
59
59
  }),
60
60
  ).rejects.toThrow(Error('Server metadata does not contain authorization endpoint'));
61
61
  });
62
- it("injects 'openid' as the first scope if not provided", async () => {
63
- // eslint-disable-next-line @typescript-eslint/ban-ts-comment
64
- // @ts-ignore
65
- client._state.endpointMetadata?.credentialIssuerMetadata.authorization_endpoint = `${MOCK_URL}v1/auth/authorize`;
66
-
67
- const url = await client.createAuthorizationRequestUrl({
68
- pkce: {
69
- codeChallengeMethod: CodeChallengeMethod.S256,
70
- codeChallenge: 'mE2kPHmIprOqtkaYmESWj35yz-PB5vzdiSu0tAZ8sqs',
71
- },
72
- authorizationRequest: {
73
- scope: 'TestCredential',
74
- redirectUri: 'http://localhost:8881/cb',
75
- },
76
- });
77
-
78
- const urlSearchParams = new URLSearchParams(url.split('?')[1]);
79
- const scope = urlSearchParams.get('scope')?.split(' ');
80
-
81
- expect(scope?.[0]).toBe('openid');
82
- });
83
62
  it('throw an error if no scope and no authorization_details is provided', async () => {
84
63
  nock(MOCK_URL).get(/.*/).reply(200, {});
85
64
  nock(MOCK_URL).get(WellKnownEndpoints.OAUTH_AS).reply(200, {});
@@ -149,7 +128,7 @@ describe('OpenID4VCIClient should', () => {
149
128
  },
150
129
  }),
151
130
  ).resolves.toEqual(
152
- 'https://server.example.com/v1/auth/authorize?response_type=code&code_challenge_method=S256&code_challenge=mE2kPHmIprOqtkaYmESWj35yz-PB5vzdiSu0tAZ8sqs&authorization_details=%5B%7B%22type%22%3A%22openid_credential%22%2C%22format%22%3A%22ldp_vc%22%2C%22credential_definition%22%3A%7B%22%40context%22%3A%5B%22https%3A%2F%2Fwww%2Ew3%2Eorg%2F2018%2Fcredentials%2Fv1%22%2C%22https%3A%2F%2Fwww%2Ew3%2Eorg%2F2018%2Fcredentials%2Fexamples%2Fv1%22%5D%2C%22types%22%3A%5B%22VerifiableCredential%22%2C%22UniversityDegreeCredential%22%5D%7D%2C%22locations%22%3A%5B%22https%3A%2F%2Fserver%2Eexample%2Ecom%22%5D%7D%2C%7B%22type%22%3A%22openid_credential%22%2C%22format%22%3A%22mso_mdoc%22%2C%22doctype%22%3A%22org%2Eiso%2E18013%2E5%2E1%2EmDL%22%2C%22locations%22%3A%5B%22https%3A%2F%2Fserver%2Eexample%2Ecom%22%5D%7D%5D&redirect_uri=http%3A%2F%2Flocalhost%3A8881%2Fcb&client_id=test-client&scope=openid',
131
+ 'https://server.example.com/v1/auth/authorize?response_type=code&code_challenge_method=S256&code_challenge=mE2kPHmIprOqtkaYmESWj35yz-PB5vzdiSu0tAZ8sqs&authorization_details=%5B%7B%22type%22%3A%22openid_credential%22%2C%22format%22%3A%22ldp_vc%22%2C%22credential_definition%22%3A%7B%22%40context%22%3A%5B%22https%3A%2F%2Fwww%2Ew3%2Eorg%2F2018%2Fcredentials%2Fv1%22%2C%22https%3A%2F%2Fwww%2Ew3%2Eorg%2F2018%2Fcredentials%2Fexamples%2Fv1%22%5D%2C%22types%22%3A%5B%22VerifiableCredential%22%2C%22UniversityDegreeCredential%22%5D%7D%2C%22locations%22%3A%5B%22https%3A%2F%2Fserver%2Eexample%2Ecom%22%5D%7D%2C%7B%22type%22%3A%22openid_credential%22%2C%22format%22%3A%22mso_mdoc%22%2C%22doctype%22%3A%22org%2Eiso%2E18013%2E5%2E1%2EmDL%22%2C%22locations%22%3A%5B%22https%3A%2F%2Fserver%2Eexample%2Ecom%22%5D%7D%5D&redirect_uri=http%3A%2F%2Flocalhost%3A8881%2Fcb&client_id=test-client',
153
132
  );
154
133
  });
155
134
  it('create an authorization request url with authorization_details object property', async () => {
@@ -176,7 +155,7 @@ describe('OpenID4VCIClient should', () => {
176
155
  },
177
156
  }),
178
157
  ).resolves.toEqual(
179
- 'https://server.example.com/v1/auth/authorize?response_type=code&code_challenge_method=S256&code_challenge=mE2kPHmIprOqtkaYmESWj35yz-PB5vzdiSu0tAZ8sqs&authorization_details=%7B%22type%22%3A%22openid_credential%22%2C%22format%22%3A%22ldp_vc%22%2C%22credential_definition%22%3A%7B%22%40context%22%3A%5B%22https%3A%2F%2Fwww%2Ew3%2Eorg%2F2018%2Fcredentials%2Fv1%22%2C%22https%3A%2F%2Fwww%2Ew3%2Eorg%2F2018%2Fcredentials%2Fexamples%2Fv1%22%5D%2C%22types%22%3A%5B%22VerifiableCredential%22%2C%22UniversityDegreeCredential%22%5D%7D%2C%22locations%22%3A%5B%22https%3A%2F%2Fserver%2Eexample%2Ecom%22%5D%7D&redirect_uri=http%3A%2F%2Flocalhost%3A8881%2Fcb&client_id=test-client&scope=openid',
158
+ 'https://server.example.com/v1/auth/authorize?response_type=code&code_challenge_method=S256&code_challenge=mE2kPHmIprOqtkaYmESWj35yz-PB5vzdiSu0tAZ8sqs&authorization_details=%7B%22type%22%3A%22openid_credential%22%2C%22format%22%3A%22ldp_vc%22%2C%22credential_definition%22%3A%7B%22%40context%22%3A%5B%22https%3A%2F%2Fwww%2Ew3%2Eorg%2F2018%2Fcredentials%2Fv1%22%2C%22https%3A%2F%2Fwww%2Ew3%2Eorg%2F2018%2Fcredentials%2Fexamples%2Fv1%22%5D%2C%22types%22%3A%5B%22VerifiableCredential%22%2C%22UniversityDegreeCredential%22%5D%7D%2C%22locations%22%3A%5B%22https%3A%2F%2Fserver%2Eexample%2Ecom%22%5D%7D&redirect_uri=http%3A%2F%2Flocalhost%3A8881%2Fcb&client_id=test-client',
180
159
  );
181
160
  });
182
161
 
@@ -51,27 +51,6 @@ describe('OpenID4VCIClientV1_0_13 should', () => {
51
51
  }),
52
52
  ).rejects.toThrow(Error('Server metadata does not contain authorization endpoint'));
53
53
  });
54
- it("injects 'openid' as the first scope if not provided", async () => {
55
- // eslint-disable-next-line @typescript-eslint/ban-ts-comment
56
- // @ts-ignore
57
- client._state.endpointMetadata?.credentialIssuerMetadata.authorization_endpoint = `${MOCK_URL}v1/auth/authorize`;
58
-
59
- const url = await client.createAuthorizationRequestUrl({
60
- pkce: {
61
- codeChallengeMethod: CodeChallengeMethod.S256,
62
- codeChallenge: 'mE2kPHmIprOqtkaYmESWj35yz-PB5vzdiSu0tAZ8sqs',
63
- },
64
- authorizationRequest: {
65
- scope: 'TestCredential',
66
- redirectUri: 'http://localhost:8881/cb',
67
- },
68
- });
69
-
70
- const urlSearchParams = new URLSearchParams(url.split('?')[1]);
71
- const scope = urlSearchParams.get('scope')?.split(' ');
72
-
73
- expect(scope?.[0]).toBe('openid');
74
- });
75
54
  it('throw an error if no scope and no authorization_details is provided', async () => {
76
55
  nock(MOCK_URL).get(/.*/).reply(200, {});
77
56
  nock(MOCK_URL).get(WellKnownEndpoints.OAUTH_AS).reply(200, {});
@@ -141,7 +120,7 @@ describe('OpenID4VCIClientV1_0_13 should', () => {
141
120
  },
142
121
  }),
143
122
  ).resolves.toEqual(
144
- 'https://server.example.com/v1/auth/authorize?response_type=code&code_challenge_method=S256&code_challenge=mE2kPHmIprOqtkaYmESWj35yz-PB5vzdiSu0tAZ8sqs&authorization_details=%5B%7B%22type%22%3A%22openid_credential%22%2C%22format%22%3A%22ldp_vc%22%2C%22credential_definition%22%3A%7B%22%40context%22%3A%5B%22https%3A%2F%2Fwww%2Ew3%2Eorg%2F2018%2Fcredentials%2Fv1%22%2C%22https%3A%2F%2Fwww%2Ew3%2Eorg%2F2018%2Fcredentials%2Fexamples%2Fv1%22%5D%2C%22types%22%3A%5B%22VerifiableCredential%22%2C%22UniversityDegreeCredential%22%5D%7D%2C%22locations%22%3A%5B%22https%3A%2F%2Fserver%2Eexample%2Ecom%22%5D%7D%2C%7B%22type%22%3A%22openid_credential%22%2C%22format%22%3A%22mso_mdoc%22%2C%22doctype%22%3A%22org%2Eiso%2E18013%2E5%2E1%2EmDL%22%2C%22locations%22%3A%5B%22https%3A%2F%2Fserver%2Eexample%2Ecom%22%5D%7D%5D&redirect_uri=http%3A%2F%2Flocalhost%3A8881%2Fcb&client_id=test-client&scope=openid',
123
+ 'https://server.example.com/v1/auth/authorize?response_type=code&code_challenge_method=S256&code_challenge=mE2kPHmIprOqtkaYmESWj35yz-PB5vzdiSu0tAZ8sqs&authorization_details=%5B%7B%22type%22%3A%22openid_credential%22%2C%22format%22%3A%22ldp_vc%22%2C%22credential_definition%22%3A%7B%22%40context%22%3A%5B%22https%3A%2F%2Fwww%2Ew3%2Eorg%2F2018%2Fcredentials%2Fv1%22%2C%22https%3A%2F%2Fwww%2Ew3%2Eorg%2F2018%2Fcredentials%2Fexamples%2Fv1%22%5D%2C%22types%22%3A%5B%22VerifiableCredential%22%2C%22UniversityDegreeCredential%22%5D%7D%2C%22locations%22%3A%5B%22https%3A%2F%2Fserver%2Eexample%2Ecom%22%5D%7D%2C%7B%22type%22%3A%22openid_credential%22%2C%22format%22%3A%22mso_mdoc%22%2C%22doctype%22%3A%22org%2Eiso%2E18013%2E5%2E1%2EmDL%22%2C%22locations%22%3A%5B%22https%3A%2F%2Fserver%2Eexample%2Ecom%22%5D%7D%5D&redirect_uri=http%3A%2F%2Flocalhost%3A8881%2Fcb&client_id=test-client',
145
124
  );
146
125
  });
147
126
  it('create an authorization request url with authorization_details object property', async () => {
@@ -168,7 +147,7 @@ describe('OpenID4VCIClientV1_0_13 should', () => {
168
147
  },
169
148
  }),
170
149
  ).resolves.toEqual(
171
- 'https://server.example.com/v1/auth/authorize?response_type=code&code_challenge_method=S256&code_challenge=mE2kPHmIprOqtkaYmESWj35yz-PB5vzdiSu0tAZ8sqs&authorization_details=%7B%22type%22%3A%22openid_credential%22%2C%22format%22%3A%22ldp_vc%22%2C%22credential_definition%22%3A%7B%22%40context%22%3A%5B%22https%3A%2F%2Fwww%2Ew3%2Eorg%2F2018%2Fcredentials%2Fv1%22%2C%22https%3A%2F%2Fwww%2Ew3%2Eorg%2F2018%2Fcredentials%2Fexamples%2Fv1%22%5D%2C%22types%22%3A%5B%22VerifiableCredential%22%2C%22UniversityDegreeCredential%22%5D%7D%2C%22locations%22%3A%5B%22https%3A%2F%2Fserver%2Eexample%2Ecom%22%5D%7D&redirect_uri=http%3A%2F%2Flocalhost%3A8881%2Fcb&client_id=test-client&scope=openid',
150
+ 'https://server.example.com/v1/auth/authorize?response_type=code&code_challenge_method=S256&code_challenge=mE2kPHmIprOqtkaYmESWj35yz-PB5vzdiSu0tAZ8sqs&authorization_details=%7B%22type%22%3A%22openid_credential%22%2C%22format%22%3A%22ldp_vc%22%2C%22credential_definition%22%3A%7B%22%40context%22%3A%5B%22https%3A%2F%2Fwww%2Ew3%2Eorg%2F2018%2Fcredentials%2Fv1%22%2C%22https%3A%2F%2Fwww%2Ew3%2Eorg%2F2018%2Fcredentials%2Fexamples%2Fv1%22%5D%2C%22types%22%3A%5B%22VerifiableCredential%22%2C%22UniversityDegreeCredential%22%5D%7D%2C%22locations%22%3A%5B%22https%3A%2F%2Fserver%2Eexample%2Ecom%22%5D%7D&redirect_uri=http%3A%2F%2Flocalhost%3A8881%2Fcb&client_id=test-client',
172
151
  );
173
152
  });
174
153
 
@@ -1,12 +1,12 @@
1
1
  import * as crypto from 'crypto';
2
2
 
3
+ import { uuidv4 } from '@sphereon/oid4vc-common';
3
4
  import { Alg, Jwt, ProofOfPossessionCallbacks } from '@sphereon/oid4vci-common';
4
5
  import { CredentialMapper } from '@sphereon/ssi-types';
5
6
  import * as didts from '@transmute/did-key.js';
6
7
  import { fetch } from 'cross-fetch';
7
8
  import debug from 'debug';
8
9
  import { importJWK, JWK, SignJWT } from 'jose';
9
- import { v4 } from 'uuid';
10
10
 
11
11
  import { OpenID4VCIClientV1_0_11 } from '..';
12
12
 
@@ -94,7 +94,7 @@ async function getCredentialOffer(format: 'ldp_vc' | 'jwt_vc_json'): Promise<Cre
94
94
  credentials: ['GuestCredential'],
95
95
  grants: {
96
96
  'urn:ietf:params:oauth:grant-type:pre-authorized_code': {
97
- 'pre-authorized_code': v4().substring(0, 10),
97
+ 'pre-authorized_code': uuidv4().substring(0, 10),
98
98
  user_pin_required: false,
99
99
  },
100
100
  },
@@ -165,7 +165,7 @@ describe('ismapolis bug report #63, https://github.com/Sphereon-Opensource/OID4V
165
165
  format: 'jwt_vc_json',
166
166
  alg: Alg.ES256K,
167
167
  kid: didDocument.verificationMethod[0].id,
168
- jti: v4(),
168
+ jti: uuidv4(),
169
169
  });
170
170
  console.log(JSON.stringify(credentialResponse.credential));
171
171
  });
@@ -1,5 +1,5 @@
1
+ import { uuidv4 } from '@sphereon/oid4vc-common';
1
2
  import { AccessTokenRequest, AccessTokenRequestOpts, Jwt, OpenId4VCIVersion } from '@sphereon/oid4vci-common';
2
- import { v4 } from 'uuid';
3
3
 
4
4
  import { ProofOfPossessionBuilder } from '../ProofOfPossessionBuilder';
5
5
 
@@ -35,7 +35,7 @@ export const createJwtBearerClientAssertion = async (
35
35
  iss: clientId,
36
36
  sub: clientId,
37
37
  aud: credentialIssuer,
38
- jti: v4(),
38
+ jti: uuidv4(),
39
39
  exp: Date.now() / 1000 + 60,
40
40
  iat: Date.now() / 1000 - 60,
41
41
  },
@@ -0,0 +1,35 @@
1
+ import { dpopTokenRequestNonceError } from '@sphereon/oid4vc-common';
2
+ import { OpenIDResponse } from 'oid4vci-common';
3
+
4
+ export type RetryRequestWithDPoPNonce = { ok: true; dpopNonce: string } | { ok: false };
5
+
6
+ export function shouldRetryTokenRequestWithDPoPNonce(response: OpenIDResponse<unknown, unknown>): RetryRequestWithDPoPNonce {
7
+ if (!response.errorBody || response.errorBody.error !== dpopTokenRequestNonceError) {
8
+ return { ok: false };
9
+ }
10
+
11
+ const dPoPNonce = response.origResponse.headers.get('DPoP-Nonce');
12
+ if (!dPoPNonce) {
13
+ throw new Error('Missing required DPoP-Nonce header.');
14
+ }
15
+
16
+ return { ok: true, dpopNonce: dPoPNonce };
17
+ }
18
+
19
+ export function shouldRetryResourceRequestWithDPoPNonce(response: OpenIDResponse<unknown, unknown>): RetryRequestWithDPoPNonce {
20
+ if (!response.errorBody || response.origResponse.status !== 401) {
21
+ return { ok: false };
22
+ }
23
+
24
+ const wwwAuthenticateHeader = response.origResponse.headers.get('WWW-Authenticate');
25
+ if (!wwwAuthenticateHeader?.includes(dpopTokenRequestNonceError)) {
26
+ return { ok: false };
27
+ }
28
+
29
+ const dPoPNonce = response.origResponse.headers.get('DPoP-Nonce');
30
+ if (!dPoPNonce) {
31
+ throw new Error('Missing required DPoP-Nonce header.');
32
+ }
33
+
34
+ return { ok: true, dpopNonce: dPoPNonce };
35
+ }
@@ -19,12 +19,10 @@ export async function sendNotification(
19
19
  const error = response.errorBody?.error !== undefined;
20
20
  const result = {
21
21
  error,
22
- response: error ? await response.errorBody?.json() : undefined,
22
+ response: error ? response.errorBody : undefined,
23
23
  };
24
24
  if (error) {
25
- LOG.warning(
26
- `Notification endpoint returned an error for event '${request.event}' and id ${request.notification_id}: ${await response.errorBody?.json()}`,
27
- );
25
+ LOG.warning(`Notification endpoint returned an error for event '${request.event}' and id ${request.notification_id}: ${response.errorBody}`);
28
26
  } else {
29
27
  LOG.debug(`Notification endpoint returned success for event '${request.event}' and id ${request.notification_id}`);
30
28
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sphereon/oid4vci-client",
3
- "version": "0.15.1",
3
+ "version": "0.15.2-next.38+d361b31",
4
4
  "description": "OpenID for Verifiable Credential Issuance (OpenID4VCI) client",
5
5
  "source": "lib/index.ts",
6
6
  "main": "dist/index.js",
@@ -15,7 +15,8 @@
15
15
  "build": "tsc"
16
16
  },
17
17
  "dependencies": {
18
- "@sphereon/oid4vci-common": "0.15.1",
18
+ "@sphereon/oid4vc-common": "0.15.2-next.38+d361b31",
19
+ "@sphereon/oid4vci-common": "0.15.2-next.38+d361b31",
19
20
  "@sphereon/ssi-types": "0.28.0",
20
21
  "cross-fetch": "^3.1.8",
21
22
  "debug": "^4.3.5"
@@ -69,5 +70,5 @@
69
70
  "OIDC4VCI",
70
71
  "OID4VCI"
71
72
  ],
72
- "gitHead": "45c46724d4f4e9044156cb8cb755929f69d0aff6"
73
+ "gitHead": "d361b31ab8f318bd68abe193b4415cb29880ddda"
73
74
  }