@sphereon/oid4vci-client 0.10.4-unstable.79 → 0.10.4-unstable.80
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.
|
@@ -29,6 +29,8 @@ import { IDENTIPROOF_ISSUER_URL, IDENTIPROOF_OID4VCI_METADATA, INITIATION_TEST,
|
|
|
29
29
|
import { getMockData } from './data/VciDataFixtures';
|
|
30
30
|
|
|
31
31
|
const partialJWT = 'eyJhbGciOiJFUzI1NiJ9.eyJpc3MiOiJkaWQ6ZXhhbXBsZTplYmZlYjFmN';
|
|
32
|
+
const partialJWT_withoutDid = 'eyJhbGciOiJFUzI1NiJ9.eyJpc3MiOiJlYmZlYjFmNzEyZWJjNmYxYzI3N';
|
|
33
|
+
|
|
32
34
|
|
|
33
35
|
const jwt1_0_08: Jwt = {
|
|
34
36
|
header: { alg: Alg.ES256, kid: 'did:example:ebfeb1f712ebc6f1c276e12ec21/keys/1', typ: 'jwt' },
|
|
@@ -40,8 +42,20 @@ const jwt1_0_13: Jwt = {
|
|
|
40
42
|
payload: { iss: 'sphereon:wallet', nonce: 'tZignsnFbp', jti: 'tZignsnFbp223', aud: IDENTIPROOF_ISSUER_URL },
|
|
41
43
|
};
|
|
42
44
|
|
|
45
|
+
const jwt1_0_08_withoutDid: Jwt = {
|
|
46
|
+
header: { alg: Alg.ES256, kid: 'ebfeb1f712ebc6f1c276e12ec21/keys/1', typ: 'jwt' },
|
|
47
|
+
payload: { iss: 'sphereon:wallet', nonce: 'tZignsnFbp', jti: 'tZignsnFbp223', aud: IDENTIPROOF_ISSUER_URL },
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
const jwt1_0_13_withoutDid: Jwt = {
|
|
51
|
+
header: { alg: Alg.ES256, kid: 'ebfeb1f712ebc6f1c276e12ec21/keys/1', typ: 'openid4vci-proof+jwt' },
|
|
52
|
+
payload: { iss: 'sphereon:wallet', nonce: 'tZignsnFbp', jti: 'tZignsnFbp223', aud: IDENTIPROOF_ISSUER_URL },
|
|
53
|
+
};
|
|
54
|
+
|
|
43
55
|
const kid = 'did:example:ebfeb1f712ebc6f1c276e12ec21/keys/1';
|
|
44
56
|
|
|
57
|
+
const kid_withoutDid = 'ebfeb1f712ebc6f1c276e12ec21/keys/1';
|
|
58
|
+
|
|
45
59
|
let keypair: KeyPair;
|
|
46
60
|
|
|
47
61
|
async function proofOfPossessionCallbackFunction(args: Jwt, kid?: string): Promise<string> {
|
|
@@ -115,6 +129,43 @@ describe('Credential Request Client ', () => {
|
|
|
115
129
|
expect(result?.successBody?.credential).toEqual(mockedVC);
|
|
116
130
|
});
|
|
117
131
|
|
|
132
|
+
it('should get success credential response with kid without did', async function () {
|
|
133
|
+
const mockedVC =
|
|
134
|
+
'eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCJ9.eyJ2YyI6eyJAY29udGV4dCI6WyJodHRwczovL3d3dy53My5vcmcvMjAxOC9jcmVkZW50aWFscy92MSIsImh0dHBzOi8vd3d3LnczLm9yZy8yMDE4L2NyZWRlbnRpYWxzL2V4YW1wbGVzL3YxIl0sImlkIjoiaHR0cDovL2V4YW1wbGUuZWR1L2NyZWRlbnRpYWxzLzM3MzIiLCJ0eXBlIjpbIlZlcmlmaWFibGVDcmVkZW50aWFsIiwiVW5pdmVyc2l0eURlZ3JlZUNyZWRlbnRpYWwiXSwiaXNzdWVyIjoiaHR0cHM6Ly9leGFtcGxlLmVkdS9pc3N1ZXJzLzU2NTA0OSIsImlzc3VhbmNlRGF0ZSI6IjIwMTAtMDEtMDFUMDA6MDA6MDBaIiwiY3JlZGVudGlhbFN1YmplY3QiOnsiaWQiOiJlYmZlYjFmNzEyZWJjNmYxYzI3NmUxMmVjMjEiLCJkZWdyZWUiOnsidHlwZSI6IkJhY2hlbG9yRGVncmVlIiwibmFtZSI6IkJhY2hlbG9yIG9mIFNjaWVuY2UgYW5kIEFydHMifX19LCJpc3MiOiJodHRwczovL2V4YW1wbGUuZWR1L2lzc3VlcnMvNTY1MDQ5IiwibmJmIjoxMjYyMzA0MDAwLCJqdGkiOiJodHRwOi8vZXhhbXBsZS5lZHUvY3JlZGVudGlhbHMvMzczMiIsInN1YiI6ImViZmViMWY3MTJlYmM2ZjFjMjc2ZTEyZWMyMSIsImlhdCI6MTcxODM0OTI0MX0.ZtGycBKJUOav5eQYQYH10gjEcVYADNHhKDjntSa57jM2JoEj5ciW7tDEb6MJpFRUxrMk62AVi-OQ8dwW3HnZVw';
|
|
135
|
+
nock('https://oidc4vci.demo.spruceid.com')
|
|
136
|
+
.post(/credential/)
|
|
137
|
+
.reply(200, {
|
|
138
|
+
format: 'jwt-vc',
|
|
139
|
+
credential: mockedVC,
|
|
140
|
+
});
|
|
141
|
+
const credReqClient = CredentialRequestClientBuilder.fromCredentialOfferRequest({ request: INITIATION_TEST })
|
|
142
|
+
.withCredentialEndpoint('https://oidc4vci.demo.spruceid.com/credential')
|
|
143
|
+
.withFormat('jwt_vc')
|
|
144
|
+
.withCredentialType('https://imsglobal.github.io/openbadges-specification/ob_v3p0.html#OpenBadgeCredential')
|
|
145
|
+
.build();
|
|
146
|
+
const proof: ProofOfPossession = await ProofOfPossessionBuilder.fromJwt({
|
|
147
|
+
jwt: jwt1_0_13_withoutDid,
|
|
148
|
+
callbacks: {
|
|
149
|
+
signCallback: proofOfPossessionCallbackFunction,
|
|
150
|
+
},
|
|
151
|
+
version: OpenId4VCIVersion.VER_1_0_13,
|
|
152
|
+
})
|
|
153
|
+
// .withEndpointMetadata(metadata)
|
|
154
|
+
.withKid(kid_withoutDid)
|
|
155
|
+
.withClientId('sphereon:wallet')
|
|
156
|
+
.build();
|
|
157
|
+
const credentialRequest = await credReqClient.createCredentialRequest({
|
|
158
|
+
credentialType: 'OpenBadgeCredential',
|
|
159
|
+
proofInput: proof,
|
|
160
|
+
format: 'jwt',
|
|
161
|
+
version: OpenId4VCIVersion.VER_1_0_13,
|
|
162
|
+
});
|
|
163
|
+
expect(credentialRequest.proof?.jwt?.includes(partialJWT_withoutDid)).toBeTruthy();
|
|
164
|
+
expect(credentialRequest.format).toEqual('jwt_vc');
|
|
165
|
+
const result = await credReqClient.acquireCredentialsUsingRequest(credentialRequest);
|
|
166
|
+
expect(result?.successBody?.credential).toEqual(mockedVC);
|
|
167
|
+
});
|
|
168
|
+
|
|
118
169
|
it('should fail with invalid url', async () => {
|
|
119
170
|
const credReqClient = CredentialRequestClientBuilder.fromCredentialOfferRequest({ request: INITIATION_TEST })
|
|
120
171
|
.withCredentialEndpoint('httpsf://oidc4vci.demo.spruceid.com/credential')
|
|
@@ -136,6 +187,28 @@ describe('Credential Request Client ', () => {
|
|
|
136
187
|
Error(URL_NOT_VALID),
|
|
137
188
|
);
|
|
138
189
|
});
|
|
190
|
+
|
|
191
|
+
it('should fail with invalid url', async () => {
|
|
192
|
+
const credReqClient = CredentialRequestClientBuilder.fromCredentialOfferRequest({ request: INITIATION_TEST })
|
|
193
|
+
.withCredentialEndpoint('httpsf://oidc4vci.demo.spruceid.com/credential')
|
|
194
|
+
.withFormat('jwt_vc')
|
|
195
|
+
.withCredentialType('https://imsglobal.github.io/openbadges-specification/ob_v3p0.html#OpenBadgeCredential')
|
|
196
|
+
.build();
|
|
197
|
+
const proof: ProofOfPossession = await ProofOfPossessionBuilder.fromJwt({
|
|
198
|
+
jwt: jwt1_0_08_withoutDid,
|
|
199
|
+
callbacks: {
|
|
200
|
+
signCallback: proofOfPossessionCallbackFunction,
|
|
201
|
+
},
|
|
202
|
+
version: OpenId4VCIVersion.VER_1_0_08,
|
|
203
|
+
})
|
|
204
|
+
// .withEndpointMetadata(metadata)
|
|
205
|
+
.withKid(kid_withoutDid)
|
|
206
|
+
.withClientId('sphereon:wallet')
|
|
207
|
+
.build();
|
|
208
|
+
await expect(credReqClient.acquireCredentialsUsingRequest({ format: 'jwt_vc_json', types: ['random'], proof })).rejects.toThrow(
|
|
209
|
+
Error(URL_NOT_VALID),
|
|
210
|
+
);
|
|
211
|
+
});
|
|
139
212
|
});
|
|
140
213
|
|
|
141
214
|
describe('Credential Request Client with Walt.id ', () => {
|
package/lib/__tests__/IT.spec.ts
CHANGED
|
@@ -29,11 +29,14 @@ import { IDENTIPROOF_AS_METADATA, IDENTIPROOF_AS_URL, IDENTIPROOF_ISSUER_URL, ID
|
|
|
29
29
|
export const UNIT_TEST_TIMEOUT = 30000;
|
|
30
30
|
|
|
31
31
|
const ISSUER_URL = 'https://issuer.research.identiproof.io';
|
|
32
|
-
const
|
|
32
|
+
const jwtDid = {
|
|
33
33
|
header: { alg: Alg.ES256, kid: 'did:example:ebfeb1f712ebc6f1c276e12ec21/keys/1', typ: 'openid4vci-proof+jwt' },
|
|
34
34
|
payload: { iss: 'test-clientId', nonce: 'tZignsnFbp', jti: 'tZignsnFbp223', aud: ISSUER_URL },
|
|
35
35
|
};
|
|
36
|
-
|
|
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
|
+
};
|
|
37
40
|
describe('OID4VCI-Client should', () => {
|
|
38
41
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
39
42
|
async function proofOfPossessionCallbackFunction(_args: Jwt, _kid?: string): Promise<string> {
|
|
@@ -202,7 +205,7 @@ describe('OID4VCI-Client should', () => {
|
|
|
202
205
|
// Types of parameters 'args' and 'args' are incompatible.
|
|
203
206
|
// Property 'kid' is missing in type '{ header: unknown; payload: unknown; }' but required in type 'ProofOfPossessionCallbackArgs'.
|
|
204
207
|
const proof: ProofOfPossession = await ProofOfPossessionBuilder.fromJwt({
|
|
205
|
-
jwt,
|
|
208
|
+
jwt: jwtDid,
|
|
206
209
|
callbacks: {
|
|
207
210
|
signCallback: proofOfPossessionCallbackFunction,
|
|
208
211
|
},
|
|
@@ -221,6 +224,66 @@ describe('OID4VCI-Client should', () => {
|
|
|
221
224
|
UNIT_TEST_TIMEOUT,
|
|
222
225
|
);
|
|
223
226
|
|
|
227
|
+
it(
|
|
228
|
+
'succeed with a full flow with a not-did-kid without the client v1_0_11',
|
|
229
|
+
async () => {
|
|
230
|
+
/* Convert the URI into an object */
|
|
231
|
+
const credentialOffer: CredentialOfferRequestWithBaseUrl = await CredentialOfferClientV1_0_11.fromURI(INITIATE_QR_V1_0_08);
|
|
232
|
+
|
|
233
|
+
expect(credentialOffer.baseUrl).toEqual('openid-initiate-issuance://');
|
|
234
|
+
expect(credentialOffer.original_credential_offer).toEqual({
|
|
235
|
+
credential_type: ['OpenBadgeCredentialUrl'],
|
|
236
|
+
issuer: ISSUER_URL,
|
|
237
|
+
'pre-authorized_code':
|
|
238
|
+
'4jLs9xZHEfqcoow0kHE7d1a8hUk6Sy-5bVSV2MqBUGUgiFFQi-ImL62T-FmLIo8hKA1UdMPH0lM1xAgcFkJfxIw9L-lI3mVs0hRT8YVwsEM1ma6N3wzuCdwtMU4bcwKp',
|
|
239
|
+
user_pin_required: 'true',
|
|
240
|
+
});
|
|
241
|
+
|
|
242
|
+
nock(ISSUER_URL)
|
|
243
|
+
.post(/token.*/)
|
|
244
|
+
.reply(200, JSON.stringify(mockedAccessTokenResponse));
|
|
245
|
+
|
|
246
|
+
/* The actual access token calls */
|
|
247
|
+
const accessTokenClient: AccessTokenClientV1_0_11 = new AccessTokenClientV1_0_11();
|
|
248
|
+
const accessTokenResponse = await accessTokenClient.acquireAccessToken({ credentialOffer: credentialOffer, pin: '1234' });
|
|
249
|
+
expect(accessTokenResponse.successBody).toEqual(mockedAccessTokenResponse);
|
|
250
|
+
// Get the credential
|
|
251
|
+
nock(ISSUER_URL)
|
|
252
|
+
.post(/credential/)
|
|
253
|
+
.reply(200, {
|
|
254
|
+
format: 'jwt-vc',
|
|
255
|
+
credential: mockedVC,
|
|
256
|
+
});
|
|
257
|
+
const credReqClient = CredentialRequestClientBuilderV1_0_11.fromCredentialOffer({ credentialOffer: credentialOffer })
|
|
258
|
+
.withFormat('jwt_vc')
|
|
259
|
+
|
|
260
|
+
.withTokenFromResponse(accessTokenResponse.successBody!)
|
|
261
|
+
.build();
|
|
262
|
+
|
|
263
|
+
//TS2322: Type '(args: ProofOfPossessionCallbackArgs) => Promise<string>'
|
|
264
|
+
// is not assignable to type 'ProofOfPossessionCallback'.
|
|
265
|
+
// Types of parameters 'args' and 'args' are incompatible.
|
|
266
|
+
// Property 'kid' is missing in type '{ header: unknown; payload: unknown; }' but required in type 'ProofOfPossessionCallbackArgs'.
|
|
267
|
+
const proof: ProofOfPossession = await ProofOfPossessionBuilder.fromJwt({
|
|
268
|
+
jwt: jwtWithoutDid,
|
|
269
|
+
callbacks: {
|
|
270
|
+
signCallback: proofOfPossessionCallbackFunction,
|
|
271
|
+
},
|
|
272
|
+
version: OpenId4VCIVersion.VER_1_0_11,
|
|
273
|
+
})
|
|
274
|
+
.withEndpointMetadata({
|
|
275
|
+
issuer: 'https://issuer.research.identiproof.io',
|
|
276
|
+
credential_endpoint: 'https://issuer.research.identiproof.io/credential',
|
|
277
|
+
token_endpoint: 'https://issuer.research.identiproof.io/token',
|
|
278
|
+
})
|
|
279
|
+
.withKid('ebfeb1f712ebc6f1c276e12ec21/keys/1')
|
|
280
|
+
.build();
|
|
281
|
+
const credResponse = await credReqClient.acquireCredentialsUsingProof({ proofInput: proof });
|
|
282
|
+
expect(credResponse.successBody?.credential).toEqual(mockedVC);
|
|
283
|
+
},
|
|
284
|
+
UNIT_TEST_TIMEOUT,
|
|
285
|
+
);
|
|
286
|
+
|
|
224
287
|
it(
|
|
225
288
|
'succeed with a full flow without the client v1_0_13',
|
|
226
289
|
async () => {
|
|
@@ -266,7 +329,7 @@ describe('OID4VCI-Client should', () => {
|
|
|
266
329
|
// Types of parameters 'args' and 'args' are incompatible.
|
|
267
330
|
// Property 'kid' is missing in type '{ header: unknown; payload: unknown; }' but required in type 'ProofOfPossessionCallbackArgs'.
|
|
268
331
|
const proof: ProofOfPossession = await ProofOfPossessionBuilder.fromJwt({
|
|
269
|
-
jwt,
|
|
332
|
+
jwt: jwtDid,
|
|
270
333
|
callbacks: {
|
|
271
334
|
signCallback: proofOfPossessionCallbackFunction,
|
|
272
335
|
},
|
|
@@ -287,6 +350,73 @@ describe('OID4VCI-Client should', () => {
|
|
|
287
350
|
},
|
|
288
351
|
UNIT_TEST_TIMEOUT,
|
|
289
352
|
);
|
|
353
|
+
|
|
354
|
+
it(
|
|
355
|
+
'succeed with a full flow with a not-did-kid without the client v1_0_13',
|
|
356
|
+
async () => {
|
|
357
|
+
/* Convert the URI into an object */
|
|
358
|
+
const credentialOffer: CredentialOfferRequestWithBaseUrl = await CredentialOfferClient.fromURI(INITIATE_QR_V1_0_13);
|
|
359
|
+
const preAuthorizedCode = 'oaKazRN8I0IbtZ0C7JuMn5';
|
|
360
|
+
expect(credentialOffer.baseUrl).toEqual('openid-credential-offer://');
|
|
361
|
+
expect((credentialOffer.credential_offer as CredentialOfferPayloadV1_0_13).credential_configuration_ids).toEqual(['OpenBadgeCredentialUrl']);
|
|
362
|
+
expect(credentialOffer.original_credential_offer.grants).toEqual({
|
|
363
|
+
'urn:ietf:params:oauth:grant-type:pre-authorized_code': {
|
|
364
|
+
'pre-authorized_code': preAuthorizedCode,
|
|
365
|
+
tx_code: {
|
|
366
|
+
input_mode: 'text',
|
|
367
|
+
description: 'Please enter the serial number of your physical drivers license',
|
|
368
|
+
length: preAuthorizedCode.length,
|
|
369
|
+
},
|
|
370
|
+
},
|
|
371
|
+
});
|
|
372
|
+
|
|
373
|
+
nock(ISSUER_URL)
|
|
374
|
+
.post(/token.*/)
|
|
375
|
+
.reply(200, JSON.stringify(mockedAccessTokenResponse));
|
|
376
|
+
|
|
377
|
+
/* The actual access token calls */
|
|
378
|
+
const accessTokenClient: AccessTokenClient = new AccessTokenClient();
|
|
379
|
+
const accessTokenResponse = await accessTokenClient.acquireAccessToken({ credentialOffer: credentialOffer, pin: '1234' });
|
|
380
|
+
expect(accessTokenResponse.successBody).toEqual(mockedAccessTokenResponse);
|
|
381
|
+
// Get the credential
|
|
382
|
+
nock(ISSUER_URL)
|
|
383
|
+
.post(/credential/)
|
|
384
|
+
.reply(200, {
|
|
385
|
+
format: 'jwt-vc',
|
|
386
|
+
credential: mockedVC,
|
|
387
|
+
});
|
|
388
|
+
const credReqClient = CredentialRequestClientBuilder.fromCredentialOffer({ credentialOffer: credentialOffer })
|
|
389
|
+
.withFormat('jwt_vc')
|
|
390
|
+
|
|
391
|
+
.withTokenFromResponse(accessTokenResponse.successBody!)
|
|
392
|
+
.build();
|
|
393
|
+
|
|
394
|
+
//TS2322: Type '(args: ProofOfPossessionCallbackArgs) => Promise<string>'
|
|
395
|
+
// is not assignable to type 'ProofOfPossessionCallback'.
|
|
396
|
+
// Types of parameters 'args' and 'args' are incompatible.
|
|
397
|
+
// Property 'kid' is missing in type '{ header: unknown; payload: unknown; }' but required in type 'ProofOfPossessionCallbackArgs'.
|
|
398
|
+
const proof: ProofOfPossession = await ProofOfPossessionBuilder.fromJwt({
|
|
399
|
+
jwt: jwtWithoutDid,
|
|
400
|
+
callbacks: {
|
|
401
|
+
signCallback: proofOfPossessionCallbackFunction,
|
|
402
|
+
},
|
|
403
|
+
version: OpenId4VCIVersion.VER_1_0_11,
|
|
404
|
+
})
|
|
405
|
+
.withEndpointMetadata({
|
|
406
|
+
issuer: 'https://issuer.research.identiproof.io',
|
|
407
|
+
credential_endpoint: 'https://issuer.research.identiproof.io/credential',
|
|
408
|
+
token_endpoint: 'https://issuer.research.identiproof.io/token',
|
|
409
|
+
})
|
|
410
|
+
.withKid('ebfeb1f712ebc6f1c276e12ec21/keys/1')
|
|
411
|
+
.build();
|
|
412
|
+
const credResponse = await credReqClient.acquireCredentialsUsingProof({
|
|
413
|
+
proofInput: proof,
|
|
414
|
+
credentialType: credentialOffer.original_credential_offer.credential_configuration_ids[0],
|
|
415
|
+
});
|
|
416
|
+
expect(credResponse.successBody?.credential).toEqual(mockedVC);
|
|
417
|
+
},
|
|
418
|
+
UNIT_TEST_TIMEOUT,
|
|
419
|
+
);
|
|
290
420
|
});
|
|
291
421
|
|
|
292
422
|
describe('OIDVCI-Client for v1_0_13 should', () => {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sphereon/oid4vci-client",
|
|
3
|
-
"version": "0.10.4-unstable.
|
|
3
|
+
"version": "0.10.4-unstable.80+85e42c5",
|
|
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,7 @@
|
|
|
15
15
|
"build": "tsc"
|
|
16
16
|
},
|
|
17
17
|
"dependencies": {
|
|
18
|
-
"@sphereon/oid4vci-common": "0.10.4-unstable.
|
|
18
|
+
"@sphereon/oid4vci-common": "0.10.4-unstable.80+85e42c5",
|
|
19
19
|
"@sphereon/ssi-types": "^0.23.0",
|
|
20
20
|
"cross-fetch": "^3.1.8",
|
|
21
21
|
"debug": "^4.3.4"
|
|
@@ -69,5 +69,5 @@
|
|
|
69
69
|
"OIDC4VCI",
|
|
70
70
|
"OID4VCI"
|
|
71
71
|
],
|
|
72
|
-
"gitHead": "
|
|
72
|
+
"gitHead": "85e42c51795ce4317d4e2d935b0e02f7b6fb4792"
|
|
73
73
|
}
|