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

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 +31 -16
  21. package/dist/OpenID4VCIClient.js.map +1 -1
  22. package/dist/OpenID4VCIClientV1_0_11.d.ts +3 -2
  23. package/dist/OpenID4VCIClientV1_0_11.d.ts.map +1 -1
  24. package/dist/OpenID4VCIClientV1_0_11.js +26 -10
  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 +26 -12
  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 +33 -6
  48. package/lib/OpenID4VCIClientV1_0_11.ts +32 -5
  49. package/lib/OpenID4VCIClientV1_0_13.ts +30 -5
  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
@@ -13,32 +13,52 @@ import {
13
13
  // @ts-ignore
14
14
  import nock from 'nock';
15
15
 
16
- import {
17
- AccessTokenClient,
18
- AccessTokenClientV1_0_11,
19
- CredentialOfferClientV1_0_11,
20
- CredentialRequestClientBuilder,
21
- CredentialRequestClientBuilderV1_0_11,
22
- OpenID4VCIClientV1_0_11,
23
- ProofOfPossessionBuilder,
24
- } from '..';
16
+ import { AccessTokenClient, AccessTokenClientV1_0_11, OpenID4VCIClient, OpenID4VCIClientV1_0_13, ProofOfPossessionBuilder } from '..';
25
17
  import { CredentialOfferClient } from '../CredentialOfferClient';
18
+ import { CredentialRequestClientBuilder } from '../CredentialRequestClientBuilder';
26
19
 
27
- import { IDENTIPROOF_AS_METADATA, IDENTIPROOF_AS_URL, IDENTIPROOF_ISSUER_URL, IDENTIPROOF_OID4VCI_METADATA } from './MetadataMocks';
20
+ import {
21
+ IDENTIPROOF_AS_METADATA,
22
+ IDENTIPROOF_AS_URL,
23
+ IDENTIPROOF_ISSUER_URL,
24
+ IDENTIPROOF_OID4VCI_METADATA,
25
+ IDENTIPROOF_OID4VCI_METADATA_v13,
26
+ } from './MetadataMocks';
28
27
 
29
28
  export const UNIT_TEST_TIMEOUT = 30000;
30
29
 
31
30
  const ISSUER_URL = 'https://issuer.research.identiproof.io';
32
- const jwt = {
31
+ const jwtDid = {
33
32
  header: { alg: Alg.ES256, kid: 'did:example:ebfeb1f712ebc6f1c276e12ec21/keys/1', typ: 'openid4vci-proof+jwt' },
34
33
  payload: { iss: 'test-clientId', nonce: 'tZignsnFbp', jti: 'tZignsnFbp223', aud: ISSUER_URL },
35
34
  };
36
35
 
36
+ const jwtWithoutDid = {
37
+ header: { alg: Alg.ES256, kid: 'ebfeb1f712ebc6f1c276e12ec21/keys/1', typ: 'openid4vci-proof+jwt' },
38
+ payload: { iss: 'test-clientId', nonce: 'tZignsnFbp', jti: 'tZignsnFbp223', aud: ISSUER_URL },
39
+ };
40
+
41
+ const mockedVC =
42
+ 'eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCJ9.eyJ2YyI6eyJAY29udGV4dCI6WyJodHRwczovL3d3dy53My5vcmcvMjAxOC9jcmVkZW50aWFscy92MSIsImh0dHBzOi8vd3d3LnczLm9yZy8yMDE4L2NyZWRlbnRpYWxzL2V4YW1wbGVzL3YxIl0sImlkIjoiaHR0cDovL2V4YW1wbGUuZWR1L2NyZWRlbnRpYWxzLzM3MzIiLCJ0eXBlIjpbIlZlcmlmaWFibGVDcmVkZW50aWFsIiwiVW5pdmVyc2l0eURlZ3JlZUNyZWRlbnRpYWwiXSwiaXNzdWVyIjoiaHR0cHM6Ly9leGFtcGxlLmVkdS9pc3N1ZXJzLzU2NTA0OSIsImlzc3VhbmNlRGF0ZSI6IjIwMTAtMDEtMDFUMDA6MDA6MDBaIiwiY3JlZGVudGlhbFN1YmplY3QiOnsiaWQiOiJkaWQ6ZXhhbXBsZTplYmZlYjFmNzEyZWJjNmYxYzI3NmUxMmVjMjEiLCJkZWdyZWUiOnsidHlwZSI6IkJhY2hlbG9yRGVncmVlIiwibmFtZSI6IkJhY2hlbG9yIG9mIFNjaWVuY2UgYW5kIEFydHMifX19LCJpc3MiOiJodHRwczovL2V4YW1wbGUuZWR1L2lzc3VlcnMvNTY1MDQ5IiwibmJmIjoxMjYyMzA0MDAwLCJqdGkiOiJodHRwOi8vZXhhbXBsZS5lZHUvY3JlZGVudGlhbHMvMzczMiIsInN1YiI6ImRpZDpleGFtcGxlOmViZmViMWY3MTJlYmM2ZjFjMjc2ZTEyZWMyMSJ9.z5vgMTK1nfizNCg5N-niCOL3WUIAL7nXy-nGhDZYO_-PNGeE-0djCpWAMH8fD8eWSID5PfkPBYkx_dfLJnQ7NA';
43
+
44
+ // Access token mocks
45
+ const mockedAccessTokenResponse: AccessTokenResponse = {
46
+ access_token: 'ey6546.546654.64565',
47
+ authorization_pending: false,
48
+ c_nonce: 'c_nonce2022101300',
49
+ c_nonce_expires_in: 2025101300,
50
+ interval: 2025101300,
51
+ token_type: 'Bearer',
52
+ };
53
+
54
+ const INITIATE_QR_V1_0_13 =
55
+ 'openid-credential-offer://?credential_offer=%7B%22credential_issuer%22:%22https://issuer.research.identiproof.io%22,%22credential_configuration_ids%22:%5B%22OpenBadgeCredentialUrl%22%5D,%22grants%22:%7B%22urn:ietf:params:oauth:grant-type:pre-authorized_code%22:%7B%22pre-authorized_code%22:%22oaKazRN8I0IbtZ0C7JuMn5%22,%22tx_code%22:%7B%22input_mode%22:%22text%22,%22length%22:22,%22description%22:%22Please%20enter%20the%20serial%20number%20of%20your%20physical%20drivers%20license%22%7D%7D%7D%7D';
56
+
57
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
58
+ async function proofOfPossessionCallbackFunction(_args: Jwt, _kid?: string): Promise<string> {
59
+ return 'ey.val.ue';
60
+ }
37
61
  describe('OID4VCI-Client should', () => {
38
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
39
- async function proofOfPossessionCallbackFunction(_args: Jwt, _kid?: string): Promise<string> {
40
- return 'ey.val.ue';
41
- }
42
62
  beforeEach(() => {
43
63
  nock.cleanAll();
44
64
  });
@@ -55,8 +75,6 @@ describe('OID4VCI-Client should', () => {
55
75
  interval: 2025101300,
56
76
  token_type: 'Bearer',
57
77
  };
58
- const mockedVC =
59
- 'eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCJ9.eyJ2YyI6eyJAY29udGV4dCI6WyJodHRwczovL3d3dy53My5vcmcvMjAxOC9jcmVkZW50aWFscy92MSIsImh0dHBzOi8vd3d3LnczLm9yZy8yMDE4L2NyZWRlbnRpYWxzL2V4YW1wbGVzL3YxIl0sImlkIjoiaHR0cDovL2V4YW1wbGUuZWR1L2NyZWRlbnRpYWxzLzM3MzIiLCJ0eXBlIjpbIlZlcmlmaWFibGVDcmVkZW50aWFsIiwiVW5pdmVyc2l0eURlZ3JlZUNyZWRlbnRpYWwiXSwiaXNzdWVyIjoiaHR0cHM6Ly9leGFtcGxlLmVkdS9pc3N1ZXJzLzU2NTA0OSIsImlzc3VhbmNlRGF0ZSI6IjIwMTAtMDEtMDFUMDA6MDA6MDBaIiwiY3JlZGVudGlhbFN1YmplY3QiOnsiaWQiOiJkaWQ6ZXhhbXBsZTplYmZlYjFmNzEyZWJjNmYxYzI3NmUxMmVjMjEiLCJkZWdyZWUiOnsidHlwZSI6IkJhY2hlbG9yRGVncmVlIiwibmFtZSI6IkJhY2hlbG9yIG9mIFNjaWVuY2UgYW5kIEFydHMifX19LCJpc3MiOiJodHRwczovL2V4YW1wbGUuZWR1L2lzc3VlcnMvNTY1MDQ5IiwibmJmIjoxMjYyMzA0MDAwLCJqdGkiOiJodHRwOi8vZXhhbXBsZS5lZHUvY3JlZGVudGlhbHMvMzczMiIsInN1YiI6ImRpZDpleGFtcGxlOmViZmViMWY3MTJlYmM2ZjFjMjc2ZTEyZWMyMSJ9.z5vgMTK1nfizNCg5N-niCOL3WUIAL7nXy-nGhDZYO_-PNGeE-0djCpWAMH8fD8eWSID5PfkPBYkx_dfLJnQ7NA';
60
78
  const INITIATE_QR_V1_0_08 =
61
79
  'openid-initiate-issuance://?issuer=https%3A%2F%2Fissuer.research.identiproof.io&credential_type=OpenBadgeCredentialUrl&pre-authorized_code=4jLs9xZHEfqcoow0kHE7d1a8hUk6Sy-5bVSV2MqBUGUgiFFQi-ImL62T-FmLIo8hKA1UdMPH0lM1xAgcFkJfxIw9L-lI3mVs0hRT8YVwsEM1ma6N3wzuCdwtMU4bcwKp&user_pin_required=true';
62
80
  const OFFER_QR_V1_0_08 =
@@ -67,14 +85,14 @@ describe('OID4VCI-Client should', () => {
67
85
  'https://issuer.research.identiproof.io?credential_offer=%7B%22credential_issuer%22%3A%22https%3A%2F%2Fissuer.research.identiproof.io%22%2C%22credentials%22%3A%5B%7B%22format%22%3A%22jwt_vc_json%22%2C%22types%22%3A%5B%22VerifiableCredential%22%2C%22UniversityDegreeCredential%22%5D%7D%5D%2C%22grants%22%3A%7B%22authorization_code%22%3A%7B%22issuer_state%22%3A%22eyJhbGciOiJSU0Et...FYUaBy%22%7D%7D%7D';
68
86
  const HTTPS_OFFER_QR_PRE_AUTHORIZED =
69
87
  'https://issuer.research.identiproof.io?credential_offer=%7B%22credential_issuer%22%3A%22https%3A%2F%2Fissuer.research.identiproof.io%22%2C%22credentials%22%3A%5B%7B%22format%22%3A%22jwt_vc_json%22%2C%22types%22%3A%5B%22VerifiableCredential%22%2C%22UniversityDegreeCredential%22%5D%7D%5D%2C%22grants%22%3A%7B%22urn%3Aietf%3Aparams%3Aoauth%3Agrant-type%3Apre-authorized_code%22%3A%7B%22pre-authorized_code%22%3A%22adhjhdjajkdkhjhdj%22%2C%22user_pin_required%22%3Atrue%7D%7D%7D';
70
-
71
- const INITIATE_QR_V1_0_13 =
72
- 'openid-credential-offer://?credential_offer=%7B%22credential_issuer%22:%22https://issuer.research.identiproof.io%22,%22credential_configuration_ids%22:%5B%22OpenBadgeCredentialUrl%22%5D,%22grants%22:%7B%22urn:ietf:params:oauth:grant-type:pre-authorized_code%22:%7B%22pre-authorized_code%22:%22oaKazRN8I0IbtZ0C7JuMn5%22,%22tx_code%22:%7B%22input_mode%22:%22text%22,%22length%22:22,%22description%22:%22Please%20enter%20the%20serial%20number%20of%20your%20physical%20drivers%20license%22%7D%7D%7D%7D';
88
+ const HTTPS_OFFER_QR_PRE_AUTHORIZED_v13 =
89
+ 'https://issuer.research.identiproof.io?credential_offer=%7B%0A%20%20%20%20%22credential_issuer%22%3A%20%22https%3A%2F%2Fissuer.research.identiproof.io%22%2C%0A%20%20%20%20%22credential_configuration_ids%22%3A%20%5B%0A%20%20%20%20%20%20%20%20%22UniversityDegreeCredential%22%0A%20%20%20%20%5D%2C%0A%20%20%20%20%22grants%22%3A%20%7B%0A%20%20%20%20%20%20%20%20%22urn%3Aietf%3Aparams%3Aoauth%3Agrant-type%3Apre-authorized_code%22%3A%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%22pre-authorized_code%22%3A%20%22adhjhdjajkdkhjhdj%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%22tx_code%22%3A%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22length%22%3A%204%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22input_mode%22%3A%20%22numeric%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22description%22%3A%20%22Please%20provide%20the%20one-time%20code%20that%20was%20sent%20via%20e-mail%22%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%7D%0A%7D';
73
90
 
74
91
  function succeedWithAFullFlowWithClientSetup() {
75
92
  nock(IDENTIPROOF_ISSUER_URL).get('/.well-known/openid-credential-issuer').reply(200, JSON.stringify(IDENTIPROOF_OID4VCI_METADATA));
76
93
  nock(IDENTIPROOF_AS_URL).get('/.well-known/oauth-authorization-server').reply(200, JSON.stringify(IDENTIPROOF_AS_METADATA));
77
94
  nock(IDENTIPROOF_AS_URL).get(WellKnownEndpoints.OPENID_CONFIGURATION).reply(404, {});
95
+ nock(IDENTIPROOF_ISSUER_URL).get(WellKnownEndpoints.OPENID_CONFIGURATION).reply(200, {});
78
96
  nock(IDENTIPROOF_AS_URL)
79
97
  .post(/oauth2\/token.*/)
80
98
  .reply(200, JSON.stringify(mockedAccessTokenResponse));
@@ -88,7 +106,7 @@ describe('OID4VCI-Client should', () => {
88
106
 
89
107
  it('succeed with a full flow with the client using OpenID4VCI version 9', async () => {
90
108
  succeedWithAFullFlowWithClientSetup();
91
- const client = await OpenID4VCIClientV1_0_11.fromURI({
109
+ const client = await OpenID4VCIClient.fromURI({
92
110
  uri: INITIATE_QR_V1_0_08,
93
111
  kid: 'did:example:ebfeb1f712ebc6f1c276e12ec21/keys/1',
94
112
  alg: Alg.ES256,
@@ -99,7 +117,7 @@ describe('OID4VCI-Client should', () => {
99
117
 
100
118
  it('succeed with a full flow with the client using OpenID4VCI version 11 and deeplink', async () => {
101
119
  succeedWithAFullFlowWithClientSetup();
102
- const client = await OpenID4VCIClientV1_0_11.fromURI({
120
+ const client = await OpenID4VCIClient.fromURI({
103
121
  uri: OFFER_QR_V1_0_08,
104
122
  kid: 'did:example:ebfeb1f712ebc6f1c276e12ec21/keys/1',
105
123
  alg: Alg.ES256,
@@ -110,7 +128,7 @@ describe('OID4VCI-Client should', () => {
110
128
 
111
129
  it('succeed with a full flow with the client using OpenID4VCI draft < 9 and https', async () => {
112
130
  succeedWithAFullFlowWithClientSetup();
113
- const client = await OpenID4VCIClientV1_0_11.fromURI({
131
+ const client = await OpenID4VCIClient.fromURI({
114
132
  uri: HTTPS_INITIATE_QR,
115
133
  kid: 'did:example:ebfeb1f712ebc6f1c276e12ec21/keys/1',
116
134
  alg: Alg.ES256,
@@ -121,7 +139,7 @@ describe('OID4VCI-Client should', () => {
121
139
 
122
140
  it('should succeed with a full flow with the client using OpenID4VCI draft > 11, https and authorization_code flow', async () => {
123
141
  succeedWithAFullFlowWithClientSetup();
124
- const client = await OpenID4VCIClientV1_0_11.fromURI({
142
+ const client = await OpenID4VCIClient.fromURI({
125
143
  uri: HTTPS_OFFER_QR_AUTHORIZATION_CODE,
126
144
  kid: 'did:example:ebfeb1f712ebc6f1c276e12ec21/keys/1',
127
145
  alg: Alg.ES256,
@@ -132,7 +150,65 @@ describe('OID4VCI-Client should', () => {
132
150
 
133
151
  it('should succeed with a full flow with the client using OpenID4VCI draft > 11, https and preauthorized_code flow', async () => {
134
152
  succeedWithAFullFlowWithClientSetup();
135
- const client = await OpenID4VCIClientV1_0_11.fromURI({
153
+ const client = await OpenID4VCIClient.fromURI({
154
+ uri: HTTPS_OFFER_QR_PRE_AUTHORIZED,
155
+ kid: 'did:example:ebfeb1f712ebc6f1c276e12ec21/keys/1',
156
+ alg: Alg.ES256,
157
+ clientId: 'test-clientId',
158
+ });
159
+ await assertionOfsucceedWithAFullFlowWithClient(client);
160
+ });
161
+
162
+ it('should succeed with a full flow with the client using OpenID4VCI draft >= 13, https and preauthorized_code flow without did', async () => {
163
+ nock(IDENTIPROOF_ISSUER_URL)
164
+ .get(WellKnownEndpoints.OPENID_CONFIGURATION)
165
+ .reply(200, {
166
+ token_endpoint: `${IDENTIPROOF_ISSUER_URL}/token`,
167
+ authorization_endpoint: `${IDENTIPROOF_ISSUER_URL}/authorize`,
168
+ });
169
+ nock(IDENTIPROOF_ISSUER_URL).post('/token').reply(200, {
170
+ access_token: 'ey6546.546654.64565',
171
+ authorization_pending: false,
172
+ c_nonce: 'c_nonce2022101300',
173
+ c_nonce_expires_in: 2025101300,
174
+ interval: 2025101300,
175
+ token_type: 'Bearer',
176
+ });
177
+ nock(IDENTIPROOF_ISSUER_URL).get('/.well-known/openid-credential-issuer').reply(200, JSON.stringify(IDENTIPROOF_OID4VCI_METADATA_v13));
178
+ nock(ISSUER_URL)
179
+ .post(/credential/)
180
+ .reply(200, {
181
+ format: 'jwt-vc',
182
+ credential: mockedVC,
183
+ });
184
+ const client = await OpenID4VCIClientV1_0_13.fromURI({
185
+ uri: HTTPS_OFFER_QR_PRE_AUTHORIZED_v13,
186
+ kid: 'ebfeb1f712ebc6f1c276e12ec21/keys/1',
187
+ alg: Alg.ES256,
188
+ clientId: 'test-clientId',
189
+ });
190
+ expect(client.credentialOffer).toBeDefined();
191
+ expect(client.endpointMetadata).toBeDefined();
192
+ expect(client.getIssuer()).toEqual('https://issuer.research.identiproof.io');
193
+ expect(client.getCredentialEndpoint()).toEqual('https://issuer.research.identiproof.io/credential');
194
+ expect(client.getAccessTokenEndpoint()).toEqual('https://issuer.research.identiproof.io/token');
195
+
196
+ const accessToken = await client.acquireAccessToken({ pin: '1234', code: 'ABCD' });
197
+ expect(accessToken).toEqual(mockedAccessTokenResponse);
198
+
199
+ const credentialResponse = await client.acquireCredentials({
200
+ credentialIdentifier: 'OpenBadgeCredential',
201
+ format: 'jwt_vc_json-ld',
202
+ proofCallbacks: {
203
+ signCallback: proofOfPossessionCallbackFunction,
204
+ },
205
+ });
206
+ expect(credentialResponse.credential).toEqual(mockedVC);
207
+ });
208
+
209
+ it('should succeed with a full flow with the client using OpenID4VCI draft > 11, https and preauthorized_code flow', async () => {
210
+ succeedWithAFullFlowWithClientSetup();
211
+ const client = await OpenID4VCIClient.fromURI({
136
212
  uri: HTTPS_OFFER_QR_PRE_AUTHORIZED,
137
213
  kid: 'did:example:ebfeb1f712ebc6f1c276e12ec21/keys/1',
138
214
  alg: Alg.ES256,
@@ -141,7 +217,7 @@ describe('OID4VCI-Client should', () => {
141
217
  await assertionOfsucceedWithAFullFlowWithClient(client);
142
218
  });
143
219
 
144
- async function assertionOfsucceedWithAFullFlowWithClient(client: OpenID4VCIClientV1_0_11) {
220
+ async function assertionOfsucceedWithAFullFlowWithClient(client: OpenID4VCIClient) {
145
221
  expect(client.credentialOffer).toBeDefined();
146
222
  expect(client.endpointMetadata).toBeDefined();
147
223
  expect(client.getIssuer()).toEqual('https://issuer.research.identiproof.io');
@@ -165,7 +241,7 @@ describe('OID4VCI-Client should', () => {
165
241
  'succeed with a full flow without the client v1_0_11',
166
242
  async () => {
167
243
  /* Convert the URI into an object */
168
- const credentialOffer: CredentialOfferRequestWithBaseUrl = await CredentialOfferClientV1_0_11.fromURI(INITIATE_QR_V1_0_08);
244
+ const credentialOffer: CredentialOfferRequestWithBaseUrl = await CredentialOfferClient.fromURI(INITIATE_QR_V1_0_08);
169
245
 
170
246
  expect(credentialOffer.baseUrl).toEqual('openid-initiate-issuance://');
171
247
  expect(credentialOffer.original_credential_offer).toEqual({
@@ -191,18 +267,14 @@ describe('OID4VCI-Client should', () => {
191
267
  format: 'jwt-vc',
192
268
  credential: mockedVC,
193
269
  });
194
- const credReqClient = CredentialRequestClientBuilderV1_0_11.fromCredentialOffer({ credentialOffer: credentialOffer })
270
+ const credReqClient = CredentialRequestClientBuilder.fromCredentialOffer({ credentialOffer: credentialOffer })
195
271
  .withFormat('jwt_vc')
196
272
 
197
273
  .withTokenFromResponse(accessTokenResponse.successBody!)
198
274
  .build();
199
275
 
200
- //TS2322: Type '(args: ProofOfPossessionCallbackArgs) => Promise<string>'
201
- // is not assignable to type 'ProofOfPossessionCallback'.
202
- // Types of parameters 'args' and 'args' are incompatible.
203
- // Property 'kid' is missing in type '{ header: unknown; payload: unknown; }' but required in type 'ProofOfPossessionCallbackArgs'.
204
276
  const proof: ProofOfPossession = await ProofOfPossessionBuilder.fromJwt({
205
- jwt,
277
+ jwt: jwtDid,
206
278
  callbacks: {
207
279
  signCallback: proofOfPossessionCallbackFunction,
208
280
  },
@@ -261,12 +333,8 @@ describe('OID4VCI-Client should', () => {
261
333
  .withTokenFromResponse(accessTokenResponse.successBody!)
262
334
  .build();
263
335
 
264
- //TS2322: Type '(args: ProofOfPossessionCallbackArgs) => Promise<string>'
265
- // is not assignable to type 'ProofOfPossessionCallback'.
266
- // Types of parameters 'args' and 'args' are incompatible.
267
- // Property 'kid' is missing in type '{ header: unknown; payload: unknown; }' but required in type 'ProofOfPossessionCallbackArgs'.
268
336
  const proof: ProofOfPossession = await ProofOfPossessionBuilder.fromJwt({
269
- jwt,
337
+ jwt: jwtDid,
270
338
  callbacks: {
271
339
  signCallback: proofOfPossessionCallbackFunction,
272
340
  },
@@ -290,9 +358,6 @@ describe('OID4VCI-Client should', () => {
290
358
  });
291
359
 
292
360
  describe('OIDVCI-Client for v1_0_13 should', () => {
293
- const INITIATE_QR_V1_0_13_CREDENCO =
294
- 'openid-credential-offer://mijnkvk.acc.credenco.com/?credential_offer_uri=https%3A%2F%2Fmijnkvk.acc.credenco.com%2Fopenid4vc%2FcredentialOffer%3Fid%3D32fc4ebf-9e31-4149-9877-e3c0b602d559';
295
-
296
361
  const mockedCredentialOffer = {
297
362
  credential_issuer: 'https://mijnkvk.acc.credenco.com',
298
363
  credential_configuration_ids: ['BevoegdheidUittreksel_jwt_vc_json'],
@@ -320,21 +385,6 @@ describe('OIDVCI-Client for v1_0_13 should', () => {
320
385
  nock.cleanAll();
321
386
  });
322
387
 
323
- /*function succeedWithAFullFlowWithClientSetup() {
324
- nock(IDENTIPROOF_ISSUER_URL).get('/.well-known/openid-credential-issuer').reply(200, JSON.stringify(IDENTIPROOF_OID4VCI_METADATA));
325
- nock(IDENTIPROOF_AS_URL).get('/.well-known/oauth-authorization-server').reply(200, JSON.stringify(IDENTIPROOF_AS_METADATA));
326
- nock(IDENTIPROOF_AS_URL).get(WellKnownEndpoints.OPENID_CONFIGURATION).reply(404, {});
327
- nock(IDENTIPROOF_AS_URL)
328
- .post(/oauth2\/token.*!/)
329
- .reply(200, JSON.stringify(mockedAccessTokenResponse));
330
- nock(ISSUER_URL)
331
- .post(/credential/)
332
- .reply(200, {
333
- format: 'jwt-vc',
334
- credential: mockedVC,
335
- });
336
- }*/
337
-
338
388
  it('should successfully resolve the credential offer URI', async () => {
339
389
  const uri = 'https://mijnkvk.acc.credenco.com/openid4vc/credentialOffer?id=32fc4ebf-9e31-4149-9877-e3c0b602d559';
340
390
 
@@ -343,78 +393,65 @@ describe('OIDVCI-Client for v1_0_13 should', () => {
343
393
  expect(credentialOffer).toEqual(mockedCredentialOffer);
344
394
  });
345
395
 
346
- // TODO: ksadjad remove the skipped test
347
- it.skip(
348
- 'succeed credenco with a full flow without the client v1_0_13',
396
+ it(
397
+ 'succeed with a full flow without the client and without did',
349
398
  async () => {
350
399
  /* Convert the URI into an object */
351
- // openid-credential-offer://?credential_offer%3D%7B%22credential_issuer%22%3A%22https%3A%2F%2Fissuer.research.identiproof.io%22%2C%22credentials%22%3A%5B%7B%22format%22%3A%22jwt_vc_json%22%2C%22types%22%3A%5B%22VerifiableCredential%22%2C%22UniversityDegreeCredential%22%5D%7D%5D%2C%22grants%22%3A%7B%22urn%3Aietf%3Aparams%3Aoauth%3Agrant-type%3Apre-authorized_code%22%3A%7B%22pre-authorized_code%22%3A%22adhjhdjajkdkhjhdj%22%2C%22user_pin_required%22%3Atrue%7D%7D%7D
352
- const credentialOffer: CredentialOfferRequestWithBaseUrl = await CredentialOfferClient.fromURI(INITIATE_QR_V1_0_13_CREDENCO);
353
- /**
354
- * {"credential_issuer":"https://mijnkvk.acc.credenco.com","credential_configuration_ids":["BevoegdheidUittreksel_jwt_vc_json"],"grants":{"authorization_code":{"issuer_state":"32fc4ebf-9e31-4149-9877-e3c0b602d559"},"urn:ietf:params:oauth:grant-type:pre-authorized_code":{"pre-authorized_code":"eyJhbGciOiJFZERTQSJ9.eyJzdWIiOiIzMmZjNGViZi05ZTMxLTQxNDktOTg3Ny1lM2MwYjYwMmQ1NTkiLCJpc3MiOiJodHRwczovL21pam5rdmsuYWNjLmNyZWRlbmNvLmNvbSIsImF1ZCI6IlRPS0VOIn0.754aiQ87O0vHYSpRvPqAS9cLOgf-pewdeXbpLziRwsxEp9mENfaXpY62muYpzOaWcYmTOydkzhFul-NDYXJZCA"}}}
355
- */
356
- const preAuthorizedCode =
357
- 'eyJhbGciOiJFZERTQSJ9.eyJzdWIiOiIzMmZjNGViZi05ZTMxLTQxNDktOTg3Ny1lM2MwYjYwMmQ1NTkiLCJpc3MiOiJodHRwczovL21pam5rdmsuYWNjLmNyZWRlbmNvLmNvbSIsImF1ZCI6IlRPS0VOIn0.754aiQ87O0vHYSpRvPqAS9cLOgf-pewdeXbpLziRwsxEp9mENfaXpY62muYpzOaWcYmTOydkzhFul-NDYXJZCA';
358
- expect(credentialOffer.baseUrl).toEqual('openid-credential-offer://mijnkvk.acc.credenco.com/');
359
- expect((credentialOffer.credential_offer as CredentialOfferPayloadV1_0_13).credential_configuration_ids).toEqual([
360
- 'BevoegdheidUittreksel_jwt_vc_json',
361
- ]);
362
- expect(credentialOffer.original_credential_offer.grants).toEqual({
363
- authorization_code: {
364
- issuer_state: '32fc4ebf-9e31-4149-9877-e3c0b602d559',
365
- },
366
- 'urn:ietf:params:oauth:grant-type:pre-authorized_code': {
367
- 'pre-authorized_code': preAuthorizedCode,
400
+ const credentialOffer: CredentialOfferRequestWithBaseUrl = await CredentialOfferClient.fromURI(INITIATE_QR_V1_0_13);
401
+
402
+ expect(credentialOffer.baseUrl).toEqual('openid-credential-offer://');
403
+ expect(credentialOffer.original_credential_offer).toEqual({
404
+ credential_configuration_ids: ['OpenBadgeCredentialUrl'],
405
+ credential_issuer: ISSUER_URL,
406
+ grants: {
407
+ 'urn:ietf:params:oauth:grant-type:pre-authorized_code': {
408
+ 'pre-authorized_code': 'oaKazRN8I0IbtZ0C7JuMn5',
409
+ tx_code: {
410
+ description: 'Please enter the serial number of your physical drivers license',
411
+ input_mode: 'text',
412
+ length: 22,
413
+ },
414
+ },
368
415
  },
369
416
  });
370
417
 
371
- /*nock(ISSUER_URL)
372
- .post(/token.*!/)
373
- .reply(200, JSON.stringify(mockedAccessTokenResponse));*/
418
+ nock(ISSUER_URL)
419
+ .post(/token.*/)
420
+ .reply(200, JSON.stringify(mockedAccessTokenResponse));
374
421
 
375
422
  /* The actual access token calls */
376
423
  const accessTokenClient: AccessTokenClient = new AccessTokenClient();
377
- const accessTokenResponse = await accessTokenClient.acquireAccessToken({
378
- credentialOffer: credentialOffer,
379
- pin: preAuthorizedCode /*, metadata: {}*/,
380
- });
381
- expect(accessTokenResponse.successBody).toEqual({});
382
- /*// Get the credential
424
+ const accessTokenResponse = await accessTokenClient.acquireAccessToken({ credentialOffer: credentialOffer, pin: '1234' });
425
+ expect(accessTokenResponse.successBody).toEqual(mockedAccessTokenResponse);
426
+ // Get the credential
383
427
  nock(ISSUER_URL)
384
- .post(/credential/)
385
- .reply(200, {
386
- format: 'jwt-vc',
387
- credential: mockedVC,
388
- });
428
+ .post(/credential/)
429
+ .reply(200, {
430
+ format: 'jwt-vc',
431
+ credential: mockedVC,
432
+ });
389
433
  const credReqClient = CredentialRequestClientBuilder.fromCredentialOffer({ credentialOffer: credentialOffer })
390
- .withFormat('jwt_vc')
434
+ .withFormat('jwt_vc')
391
435
 
392
- .withTokenFromResponse(accessTokenResponse.successBody!)
393
- .build();
436
+ .withTokenFromResponse(accessTokenResponse.successBody!)
437
+ .build();
394
438
 
395
- //TS2322: Type '(args: ProofOfPossessionCallbackArgs) => Promise<string>'
396
- // is not assignable to type 'ProofOfPossessionCallback'.
397
- // Types of parameters 'args' and 'args' are incompatible.
398
- // Property 'kid' is missing in type '{ header: unknown; payload: unknown; }' but required in type 'ProofOfPossessionCallbackArgs'.
399
439
  const proof: ProofOfPossession = await ProofOfPossessionBuilder.fromJwt({
400
- jwt,
440
+ jwt: jwtWithoutDid,
401
441
  callbacks: {
402
442
  signCallback: proofOfPossessionCallbackFunction,
403
443
  },
404
- version: OpenId4VCIVersion.VER_1_0_11,
405
- })
406
- .withEndpointMetadata({
407
- issuer: 'https://issuer.research.identiproof.io',
408
- credential_endpoint: 'https://issuer.research.identiproof.io/credential',
409
- token_endpoint: 'https://issuer.research.identiproof.io/token',
444
+ version: OpenId4VCIVersion.VER_1_0_13,
410
445
  })
411
- .withKid('did:example:ebfeb1f712ebc6f1c276e12ec21/keys/1')
412
- .build();
413
- const credResponse = await credReqClient.acquireCredentialsUsingProof({
414
- proofInput: proof,
415
- credentialTypes: credentialOffer.original_credential_offer.credential_configuration_ids,
416
- });
417
- expect(credResponse.successBody?.credential).toEqual(mockedVC);*/
446
+ .withEndpointMetadata({
447
+ issuer: 'https://issuer.research.identiproof.io',
448
+ credential_endpoint: 'https://issuer.research.identiproof.io/credential',
449
+ token_endpoint: 'https://issuer.research.identiproof.io/token',
450
+ })
451
+ .withKid('ebfeb1f712ebc6f1c276e12ec21/keys/1')
452
+ .build();
453
+ const credResponse = await credReqClient.acquireCredentialsUsingProof({ proofInput: proof, credentialIdentifier: 'OpenBadgeCredentialUrl' });
454
+ expect(credResponse.successBody?.credential).toEqual(mockedVC);
418
455
  },
419
456
  UNIT_TEST_TIMEOUT,
420
457
  );
@@ -127,6 +127,41 @@ export const IDENTIPROOF_OID4VCI_METADATA = {
127
127
  },
128
128
  },
129
129
  };
130
+ export const IDENTIPROOF_OID4VCI_METADATA_v13 = {
131
+ issuer: 'https://issuer.research.identiproof.io',
132
+ authorization_server: 'https://auth.research.identiproof.io',
133
+ credential_endpoint: 'https://issuer.research.identiproof.io/credential',
134
+ jwks_uri: 'https://issuer.research.identiproof.io/.well-known/did.json',
135
+ credential_configurations_supported: {
136
+ 'Cyber Security Certificate': {
137
+ formats: {
138
+ jwt_vc: {
139
+ types: ['VerifiableCredential', 'Cyber Security Certificate'],
140
+ cryptographic_binding_methods_supported: ['did'],
141
+ cryptographic_suites_supported: ['ES256'],
142
+ },
143
+ },
144
+ },
145
+ OpenBadgeCredential: {
146
+ formats: {
147
+ jwt_vc: {
148
+ types: ['VerifiableCredential', 'OpenBadgeCredential'],
149
+ cryptographic_binding_methods_supported: ['did'],
150
+ cryptographic_suites_supported: ['ES256'],
151
+ },
152
+ },
153
+ },
154
+ OpenBadgeExtendedCredential: {
155
+ formats: {
156
+ jwt_vc: {
157
+ types: ['VerifiableCredential', 'OpenBadgeExtendedCredential'],
158
+ cryptographic_binding_methods_supported: ['did'],
159
+ cryptographic_suites_supported: ['ES256'],
160
+ },
161
+ },
162
+ },
163
+ },
164
+ };
130
165
 
131
166
  export const SPRUCE_OID4VCI_METADATA = {
132
167
  issuer: 'https://ngi-oidc4vci-test.spruceid.xyz',
@@ -12,8 +12,15 @@ const jwt: Jwt = {
12
12
  payload: { iss: 'sphereon:wallet', nonce: 'tZignsnFbp', jti: 'tZignsnFbp223', aud: IDENTIPROOF_ISSUER_URL, iat: Date.now() / 1000 },
13
13
  };
14
14
 
15
+ const jwt_withoutDid: Jwt = {
16
+ header: { alg: Alg.ES256, kid: 'ebfeb1f712ebc6f1c276e12ec21/keys/1', typ: 'jwt' },
17
+ payload: { iss: 'sphereon:wallet', nonce: 'tZignsnFbp', jti: 'tZignsnFbp223', aud: IDENTIPROOF_ISSUER_URL, iat: Date.now() / 1000 },
18
+ };
19
+
15
20
  const kid = 'did:example:ebfeb1f712ebc6f1c276e12ec21/keys/1';
16
21
 
22
+ const kid_withoutDid = 'ebfeb1f712ebc6f1c276e12ec21/keys/1';
23
+
17
24
  let keypair: KeyPair;
18
25
 
19
26
  async function proofOfPossessionCallbackFunction(args: Jwt, kid?: string): Promise<string> {
@@ -52,6 +59,16 @@ describe('ProofOfPossession Builder ', () => {
52
59
  ).rejects.toThrow(Error(PROOF_CANT_BE_CONSTRUCTED));
53
60
  });
54
61
 
62
+ it('should fail without supplied proof or callbacks and with kid without did', async function () {
63
+ await expect(
64
+ ProofOfPossessionBuilder.fromProof(undefined as never, OpenId4VCIVersion.VER_1_0_13)
65
+ .withIssuer(IDENTIPROOF_ISSUER_URL)
66
+ .withClientId('sphereon:wallet')
67
+ .withKid(kid_withoutDid)
68
+ .build(),
69
+ ).rejects.toThrow(Error(PROOF_CANT_BE_CONSTRUCTED));
70
+ });
71
+
55
72
  it('should fail wit undefined jwt supplied', async function () {
56
73
  await expect(() =>
57
74
  ProofOfPossessionBuilder.fromJwt({ jwt, callbacks: { signCallback: proofOfPossessionCallbackFunction }, version: OpenId4VCIVersion.VER_1_0_08 })
@@ -63,6 +80,21 @@ describe('ProofOfPossession Builder ', () => {
63
80
  ).toThrow(Error(NO_JWT_PROVIDED));
64
81
  });
65
82
 
83
+ it('should fail with undefined jwt supplied and kid without did', async function () {
84
+ await expect(() =>
85
+ ProofOfPossessionBuilder.fromJwt({
86
+ jwt: jwt_withoutDid,
87
+ callbacks: { signCallback: proofOfPossessionCallbackFunction },
88
+ version: OpenId4VCIVersion.VER_1_0_08,
89
+ })
90
+ .withJwt(undefined as never)
91
+ .withIssuer(IDENTIPROOF_ISSUER_URL)
92
+ .withClientId('sphereon:wallet')
93
+ .withKid(kid_withoutDid)
94
+ .build(),
95
+ ).toThrow(Error(NO_JWT_PROVIDED));
96
+ });
97
+
66
98
  it('should build a proof with all required params present', async function () {
67
99
  const proof: ProofOfPossession = await ProofOfPossessionBuilder.fromJwt({
68
100
  jwt,
@@ -78,6 +110,21 @@ describe('ProofOfPossession Builder ', () => {
78
110
  expect(proof).toBeDefined();
79
111
  });
80
112
 
113
+ it('should build a proof with all required params present without did', async function () {
114
+ const proof: ProofOfPossession = await ProofOfPossessionBuilder.fromJwt({
115
+ jwt: jwt_withoutDid,
116
+ callbacks: {
117
+ signCallback: proofOfPossessionCallbackFunction,
118
+ },
119
+ version: OpenId4VCIVersion.VER_1_0_08,
120
+ })
121
+ .withIssuer(IDENTIPROOF_ISSUER_URL)
122
+ .withKid(kid_withoutDid)
123
+ .withClientId('sphereon:wallet')
124
+ .build();
125
+ expect(proof).toBeDefined();
126
+ });
127
+
81
128
  it('should fail creating a proof of possession with simple verification', async () => {
82
129
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
83
130
  async function proofOfPossessionCallbackFunction(_args: Jwt, _kid?: string): Promise<string> {
@@ -93,6 +140,25 @@ describe('ProofOfPossession Builder ', () => {
93
140
  ).rejects.toThrow(Error(JWS_NOT_VALID));
94
141
  });
95
142
 
143
+ it('should fail creating a proof of possession with simple verification and without did', async () => {
144
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
145
+ async function proofOfPossessionCallbackFunction(_args: Jwt, _kid?: string): Promise<string> {
146
+ throw new Error(JWS_NOT_VALID);
147
+ }
148
+
149
+ await expect(
150
+ ProofOfPossessionBuilder.fromJwt({
151
+ jwt: jwt_withoutDid,
152
+ callbacks: { signCallback: proofOfPossessionCallbackFunction },
153
+ version: OpenId4VCIVersion.VER_1_0_08,
154
+ })
155
+ .withIssuer(IDENTIPROOF_ISSUER_URL)
156
+ .withClientId('sphereon:wallet')
157
+ .withKid(kid_withoutDid)
158
+ .build(),
159
+ ).rejects.toThrow(Error(JWS_NOT_VALID));
160
+ });
161
+
96
162
  it('should fail creating a proof of possession without verify callback', async () => {
97
163
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
98
164
  async function proofOfPossessionCallbackFunction(_args: Jwt, _kid?: string): Promise<string> {
@@ -107,4 +173,23 @@ describe('ProofOfPossession Builder ', () => {
107
173
  .build(),
108
174
  ).rejects.toThrow(Error(JWS_NOT_VALID));
109
175
  });
176
+
177
+ it('should fail creating a proof of possession without verify callback and without did', async () => {
178
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
179
+ async function proofOfPossessionCallbackFunction(_args: Jwt, _kid?: string): Promise<string> {
180
+ throw new Error(JWS_NOT_VALID);
181
+ }
182
+
183
+ await expect(
184
+ ProofOfPossessionBuilder.fromJwt({
185
+ jwt: jwt_withoutDid,
186
+ callbacks: { signCallback: proofOfPossessionCallbackFunction },
187
+ version: OpenId4VCIVersion.VER_1_0_08,
188
+ })
189
+ .withIssuer(IDENTIPROOF_ISSUER_URL)
190
+ .withClientId('sphereon:wallet')
191
+ .withKid(kid_withoutDid)
192
+ .build(),
193
+ ).rejects.toThrow(Error(JWS_NOT_VALID));
194
+ });
110
195
  });