@sphereon/oid4vci-client 0.12.1-unstable.2 → 0.12.1-unstable.3
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.
- package/lib/__tests__/IT.spec.ts +98 -296
- package/lib/__tests__/MetadataMocks.ts +35 -0
- package/package.json +3 -3
package/lib/__tests__/IT.spec.ts
CHANGED
|
@@ -1,12 +1,10 @@
|
|
|
1
1
|
import {
|
|
2
2
|
AccessTokenResponse,
|
|
3
3
|
Alg,
|
|
4
|
-
CredentialOfferPayloadV1_0_13,
|
|
5
4
|
CredentialOfferRequestWithBaseUrl,
|
|
6
5
|
Jwt,
|
|
7
6
|
OpenId4VCIVersion,
|
|
8
7
|
ProofOfPossession,
|
|
9
|
-
resolveCredentialOfferURI,
|
|
10
8
|
WellKnownEndpoints,
|
|
11
9
|
} from '@sphereon/oid4vci-common';
|
|
12
10
|
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
@@ -14,17 +12,20 @@ import {
|
|
|
14
12
|
import nock from 'nock';
|
|
15
13
|
|
|
16
14
|
import {
|
|
17
|
-
AccessTokenClient,
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
OpenID4VCIClientV1_0_11,
|
|
23
|
-
ProofOfPossessionBuilder,
|
|
24
|
-
} from '..';
|
|
15
|
+
AccessTokenClient, AccessTokenClientV1_0_11, CredentialOfferClientV1_0_13,
|
|
16
|
+
CredentialRequestClientBuilder, CredentialRequestClientBuilderV1_0_11,
|
|
17
|
+
OpenID4VCIClient, OpenID4VCIClientV1_0_13,
|
|
18
|
+
ProofOfPossessionBuilder
|
|
19
|
+
} from '..'
|
|
25
20
|
import { CredentialOfferClient } from '../CredentialOfferClient';
|
|
26
21
|
|
|
27
|
-
import {
|
|
22
|
+
import {
|
|
23
|
+
IDENTIPROOF_AS_METADATA,
|
|
24
|
+
IDENTIPROOF_AS_URL,
|
|
25
|
+
IDENTIPROOF_ISSUER_URL,
|
|
26
|
+
IDENTIPROOF_OID4VCI_METADATA,
|
|
27
|
+
IDENTIPROOF_OID4VCI_METADATA_v13
|
|
28
|
+
} from './MetadataMocks'
|
|
28
29
|
|
|
29
30
|
export const UNIT_TEST_TIMEOUT = 30000;
|
|
30
31
|
|
|
@@ -72,6 +73,8 @@ describe('OID4VCI-Client should', () => {
|
|
|
72
73
|
'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';
|
|
73
74
|
const HTTPS_OFFER_QR_PRE_AUTHORIZED =
|
|
74
75
|
'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';
|
|
76
|
+
const HTTPS_OFFER_QR_PRE_AUTHORIZED_v13 =
|
|
77
|
+
'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';
|
|
75
78
|
|
|
76
79
|
const INITIATE_QR_V1_0_13 =
|
|
77
80
|
'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';
|
|
@@ -80,6 +83,7 @@ describe('OID4VCI-Client should', () => {
|
|
|
80
83
|
nock(IDENTIPROOF_ISSUER_URL).get('/.well-known/openid-credential-issuer').reply(200, JSON.stringify(IDENTIPROOF_OID4VCI_METADATA));
|
|
81
84
|
nock(IDENTIPROOF_AS_URL).get('/.well-known/oauth-authorization-server').reply(200, JSON.stringify(IDENTIPROOF_AS_METADATA));
|
|
82
85
|
nock(IDENTIPROOF_AS_URL).get(WellKnownEndpoints.OPENID_CONFIGURATION).reply(404, {});
|
|
86
|
+
nock(IDENTIPROOF_ISSUER_URL).get(WellKnownEndpoints.OPENID_CONFIGURATION).reply(200, {});
|
|
83
87
|
nock(IDENTIPROOF_AS_URL)
|
|
84
88
|
.post(/oauth2\/token.*/)
|
|
85
89
|
.reply(200, JSON.stringify(mockedAccessTokenResponse));
|
|
@@ -93,7 +97,7 @@ describe('OID4VCI-Client should', () => {
|
|
|
93
97
|
|
|
94
98
|
it('succeed with a full flow with the client using OpenID4VCI version 9', async () => {
|
|
95
99
|
succeedWithAFullFlowWithClientSetup();
|
|
96
|
-
const client = await
|
|
100
|
+
const client = await OpenID4VCIClient.fromURI({
|
|
97
101
|
uri: INITIATE_QR_V1_0_08,
|
|
98
102
|
kid: 'did:example:ebfeb1f712ebc6f1c276e12ec21/keys/1',
|
|
99
103
|
alg: Alg.ES256,
|
|
@@ -104,7 +108,7 @@ describe('OID4VCI-Client should', () => {
|
|
|
104
108
|
|
|
105
109
|
it('succeed with a full flow with the client using OpenID4VCI version 11 and deeplink', async () => {
|
|
106
110
|
succeedWithAFullFlowWithClientSetup();
|
|
107
|
-
const client = await
|
|
111
|
+
const client = await OpenID4VCIClient.fromURI({
|
|
108
112
|
uri: OFFER_QR_V1_0_08,
|
|
109
113
|
kid: 'did:example:ebfeb1f712ebc6f1c276e12ec21/keys/1',
|
|
110
114
|
alg: Alg.ES256,
|
|
@@ -114,8 +118,8 @@ describe('OID4VCI-Client should', () => {
|
|
|
114
118
|
});
|
|
115
119
|
|
|
116
120
|
it('succeed with a full flow with the client using OpenID4VCI draft < 9 and https', async () => {
|
|
117
|
-
succeedWithAFullFlowWithClientSetup()
|
|
118
|
-
const client = await
|
|
121
|
+
succeedWithAFullFlowWithClientSetup()
|
|
122
|
+
const client = await OpenID4VCIClient.fromURI({
|
|
119
123
|
uri: HTTPS_INITIATE_QR,
|
|
120
124
|
kid: 'did:example:ebfeb1f712ebc6f1c276e12ec21/keys/1',
|
|
121
125
|
alg: Alg.ES256,
|
|
@@ -125,8 +129,8 @@ describe('OID4VCI-Client should', () => {
|
|
|
125
129
|
});
|
|
126
130
|
|
|
127
131
|
it('should succeed with a full flow with the client using OpenID4VCI draft > 11, https and authorization_code flow', async () => {
|
|
128
|
-
succeedWithAFullFlowWithClientSetup()
|
|
129
|
-
const client = await
|
|
132
|
+
succeedWithAFullFlowWithClientSetup()
|
|
133
|
+
const client = await OpenID4VCIClient.fromURI({
|
|
130
134
|
uri: HTTPS_OFFER_QR_AUTHORIZATION_CODE,
|
|
131
135
|
kid: 'did:example:ebfeb1f712ebc6f1c276e12ec21/keys/1',
|
|
132
136
|
alg: Alg.ES256,
|
|
@@ -136,8 +140,8 @@ describe('OID4VCI-Client should', () => {
|
|
|
136
140
|
});
|
|
137
141
|
|
|
138
142
|
it('should succeed with a full flow with the client using OpenID4VCI draft > 11, https and preauthorized_code flow', async () => {
|
|
139
|
-
succeedWithAFullFlowWithClientSetup()
|
|
140
|
-
const client = await
|
|
143
|
+
succeedWithAFullFlowWithClientSetup()
|
|
144
|
+
const client = await OpenID4VCIClient.fromURI({
|
|
141
145
|
uri: HTTPS_OFFER_QR_PRE_AUTHORIZED,
|
|
142
146
|
kid: 'did:example:ebfeb1f712ebc6f1c276e12ec21/keys/1',
|
|
143
147
|
alg: Alg.ES256,
|
|
@@ -146,7 +150,63 @@ describe('OID4VCI-Client should', () => {
|
|
|
146
150
|
await assertionOfsucceedWithAFullFlowWithClient(client);
|
|
147
151
|
});
|
|
148
152
|
|
|
149
|
-
|
|
153
|
+
it('should succeed with a full flow with the client using OpenID4VCI draft >= 13, https and preauthorized_code flow without did', async () => {
|
|
154
|
+
nock(IDENTIPROOF_ISSUER_URL).get(WellKnownEndpoints.OPENID_CONFIGURATION).reply(200, {
|
|
155
|
+
token_endpoint: `${IDENTIPROOF_ISSUER_URL}/token`,
|
|
156
|
+
authorization_endpoint: `${IDENTIPROOF_ISSUER_URL}/authorize`,
|
|
157
|
+
});
|
|
158
|
+
nock(IDENTIPROOF_ISSUER_URL).post('/token').reply(200, {
|
|
159
|
+
access_token: 'ey6546.546654.64565',
|
|
160
|
+
authorization_pending: false,
|
|
161
|
+
c_nonce: 'c_nonce2022101300',
|
|
162
|
+
c_nonce_expires_in: 2025101300,
|
|
163
|
+
interval: 2025101300,
|
|
164
|
+
token_type: 'Bearer',
|
|
165
|
+
})
|
|
166
|
+
nock(IDENTIPROOF_ISSUER_URL).get('/.well-known/openid-credential-issuer').reply(200, JSON.stringify(IDENTIPROOF_OID4VCI_METADATA_v13));
|
|
167
|
+
nock(ISSUER_URL)
|
|
168
|
+
.post(/credential/)
|
|
169
|
+
.reply(200, {
|
|
170
|
+
format: 'jwt-vc',
|
|
171
|
+
credential: mockedVC,
|
|
172
|
+
});
|
|
173
|
+
const client = await OpenID4VCIClientV1_0_13.fromURI({
|
|
174
|
+
uri: HTTPS_OFFER_QR_PRE_AUTHORIZED_v13,
|
|
175
|
+
kid: 'ebfeb1f712ebc6f1c276e12ec21/keys/1',
|
|
176
|
+
alg: Alg.ES256,
|
|
177
|
+
clientId: 'test-clientId',
|
|
178
|
+
});
|
|
179
|
+
expect(client.credentialOffer).toBeDefined();
|
|
180
|
+
expect(client.endpointMetadata).toBeDefined();
|
|
181
|
+
expect(client.getIssuer()).toEqual('https://issuer.research.identiproof.io');
|
|
182
|
+
expect(client.getCredentialEndpoint()).toEqual('https://issuer.research.identiproof.io/credential');
|
|
183
|
+
expect(client.getAccessTokenEndpoint()).toEqual('https://issuer.research.identiproof.io/token');
|
|
184
|
+
|
|
185
|
+
const accessToken = await client.acquireAccessToken({ pin: '1234', code: 'ABCD' });
|
|
186
|
+
expect(accessToken).toEqual(mockedAccessTokenResponse);
|
|
187
|
+
|
|
188
|
+
const credentialResponse = await client.acquireCredentials({
|
|
189
|
+
credentialIdentifier: 'OpenBadgeCredential',
|
|
190
|
+
format: 'jwt_vc_json-ld',
|
|
191
|
+
proofCallbacks: {
|
|
192
|
+
signCallback: proofOfPossessionCallbackFunction,
|
|
193
|
+
},
|
|
194
|
+
});
|
|
195
|
+
expect(credentialResponse.credential).toEqual(mockedVC);
|
|
196
|
+
});
|
|
197
|
+
|
|
198
|
+
it('should succeed with a full flow with the client using OpenID4VCI draft > 11, https and preauthorized_code flow', async () => {
|
|
199
|
+
succeedWithAFullFlowWithClientSetup()
|
|
200
|
+
const client = await OpenID4VCIClient.fromURI({
|
|
201
|
+
uri: HTTPS_OFFER_QR_PRE_AUTHORIZED,
|
|
202
|
+
kid: 'did:example:ebfeb1f712ebc6f1c276e12ec21/keys/1',
|
|
203
|
+
alg: Alg.ES256,
|
|
204
|
+
clientId: 'test-clientId',
|
|
205
|
+
});
|
|
206
|
+
await assertionOfsucceedWithAFullFlowWithClient(client);
|
|
207
|
+
});
|
|
208
|
+
|
|
209
|
+
async function assertionOfsucceedWithAFullFlowWithClient(client: OpenID4VCIClient) {
|
|
150
210
|
expect(client.credentialOffer).toBeDefined();
|
|
151
211
|
expect(client.endpointMetadata).toBeDefined();
|
|
152
212
|
expect(client.getIssuer()).toEqual('https://issuer.research.identiproof.io');
|
|
@@ -167,10 +227,10 @@ describe('OID4VCI-Client should', () => {
|
|
|
167
227
|
}
|
|
168
228
|
|
|
169
229
|
it(
|
|
170
|
-
'succeed with a full flow without the client
|
|
230
|
+
'succeed with a full flow without the client',
|
|
171
231
|
async () => {
|
|
172
232
|
/* Convert the URI into an object */
|
|
173
|
-
const credentialOffer: CredentialOfferRequestWithBaseUrl = await
|
|
233
|
+
const credentialOffer: CredentialOfferRequestWithBaseUrl = await CredentialOfferClient.fromURI(INITIATE_QR_V1_0_08);
|
|
174
234
|
|
|
175
235
|
expect(credentialOffer.baseUrl).toEqual('openid-initiate-issuance://');
|
|
176
236
|
expect(credentialOffer.original_credential_offer).toEqual({
|
|
@@ -227,149 +287,25 @@ describe('OID4VCI-Client should', () => {
|
|
|
227
287
|
);
|
|
228
288
|
|
|
229
289
|
it(
|
|
230
|
-
'succeed with a full flow
|
|
290
|
+
'succeed with a full flow without the client and without did',
|
|
231
291
|
async () => {
|
|
232
292
|
/* Convert the URI into an object */
|
|
233
|
-
const credentialOffer: CredentialOfferRequestWithBaseUrl = await
|
|
234
|
-
|
|
235
|
-
expect(credentialOffer.baseUrl).toEqual('openid-initiate-issuance://');
|
|
236
|
-
expect(credentialOffer.original_credential_offer).toEqual({
|
|
237
|
-
credential_type: ['OpenBadgeCredentialUrl'],
|
|
238
|
-
issuer: ISSUER_URL,
|
|
239
|
-
'pre-authorized_code':
|
|
240
|
-
'4jLs9xZHEfqcoow0kHE7d1a8hUk6Sy-5bVSV2MqBUGUgiFFQi-ImL62T-FmLIo8hKA1UdMPH0lM1xAgcFkJfxIw9L-lI3mVs0hRT8YVwsEM1ma6N3wzuCdwtMU4bcwKp',
|
|
241
|
-
user_pin_required: 'true',
|
|
242
|
-
});
|
|
243
|
-
|
|
244
|
-
nock(ISSUER_URL)
|
|
245
|
-
.post(/token.*/)
|
|
246
|
-
.reply(200, JSON.stringify(mockedAccessTokenResponse));
|
|
247
|
-
|
|
248
|
-
/* The actual access token calls */
|
|
249
|
-
const accessTokenClient: AccessTokenClientV1_0_11 = new AccessTokenClientV1_0_11();
|
|
250
|
-
const accessTokenResponse = await accessTokenClient.acquireAccessToken({ credentialOffer: credentialOffer, pin: '1234' });
|
|
251
|
-
expect(accessTokenResponse.successBody).toEqual(mockedAccessTokenResponse);
|
|
252
|
-
// Get the credential
|
|
253
|
-
nock(ISSUER_URL)
|
|
254
|
-
.post(/credential/)
|
|
255
|
-
.reply(200, {
|
|
256
|
-
format: 'jwt-vc',
|
|
257
|
-
credential: mockedVC,
|
|
258
|
-
});
|
|
259
|
-
const credReqClient = CredentialRequestClientBuilderV1_0_11.fromCredentialOffer({ credentialOffer: credentialOffer })
|
|
260
|
-
.withFormat('jwt_vc')
|
|
293
|
+
const credentialOffer: CredentialOfferRequestWithBaseUrl = await CredentialOfferClientV1_0_13.fromURI(INITIATE_QR_V1_0_13);
|
|
261
294
|
|
|
262
|
-
.withTokenFromResponse(accessTokenResponse.successBody!)
|
|
263
|
-
.build();
|
|
264
|
-
|
|
265
|
-
//TS2322: Type '(args: ProofOfPossessionCallbackArgs) => Promise<string>'
|
|
266
|
-
// is not assignable to type 'ProofOfPossessionCallback'.
|
|
267
|
-
// Types of parameters 'args' and 'args' are incompatible.
|
|
268
|
-
// Property 'kid' is missing in type '{ header: unknown; payload: unknown; }' but required in type 'ProofOfPossessionCallbackArgs'.
|
|
269
|
-
const proof: ProofOfPossession = await ProofOfPossessionBuilder.fromJwt({
|
|
270
|
-
jwt: jwtWithoutDid,
|
|
271
|
-
callbacks: {
|
|
272
|
-
signCallback: proofOfPossessionCallbackFunction,
|
|
273
|
-
},
|
|
274
|
-
version: OpenId4VCIVersion.VER_1_0_11,
|
|
275
|
-
})
|
|
276
|
-
.withEndpointMetadata({
|
|
277
|
-
issuer: 'https://issuer.research.identiproof.io',
|
|
278
|
-
credential_endpoint: 'https://issuer.research.identiproof.io/credential',
|
|
279
|
-
token_endpoint: 'https://issuer.research.identiproof.io/token',
|
|
280
|
-
})
|
|
281
|
-
.withKid('ebfeb1f712ebc6f1c276e12ec21/keys/1')
|
|
282
|
-
.build();
|
|
283
|
-
const credResponse = await credReqClient.acquireCredentialsUsingProof({ proofInput: proof });
|
|
284
|
-
expect(credResponse.successBody?.credential).toEqual(mockedVC);
|
|
285
|
-
},
|
|
286
|
-
UNIT_TEST_TIMEOUT,
|
|
287
|
-
);
|
|
288
|
-
|
|
289
|
-
it(
|
|
290
|
-
'succeed with a full flow without the client v1_0_13',
|
|
291
|
-
async () => {
|
|
292
|
-
/* Convert the URI into an object */
|
|
293
|
-
const credentialOffer: CredentialOfferRequestWithBaseUrl = await CredentialOfferClient.fromURI(INITIATE_QR_V1_0_13);
|
|
294
|
-
const preAuthorizedCode = 'oaKazRN8I0IbtZ0C7JuMn5';
|
|
295
295
|
expect(credentialOffer.baseUrl).toEqual('openid-credential-offer://');
|
|
296
|
-
expect(
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
nock(ISSUER_URL)
|
|
309
|
-
.post(/token.*/)
|
|
310
|
-
.reply(200, JSON.stringify(mockedAccessTokenResponse));
|
|
311
|
-
|
|
312
|
-
/* The actual access token calls */
|
|
313
|
-
const accessTokenClient: AccessTokenClient = new AccessTokenClient();
|
|
314
|
-
const accessTokenResponse = await accessTokenClient.acquireAccessToken({ credentialOffer: credentialOffer, pin: '1234' });
|
|
315
|
-
expect(accessTokenResponse.successBody).toEqual(mockedAccessTokenResponse);
|
|
316
|
-
// Get the credential
|
|
317
|
-
nock(ISSUER_URL)
|
|
318
|
-
.post(/credential/)
|
|
319
|
-
.reply(200, {
|
|
320
|
-
format: 'jwt-vc',
|
|
321
|
-
credential: mockedVC,
|
|
322
|
-
});
|
|
323
|
-
const credReqClient = CredentialRequestClientBuilder.fromCredentialOffer({ credentialOffer: credentialOffer })
|
|
324
|
-
.withFormat('jwt_vc')
|
|
325
|
-
|
|
326
|
-
.withTokenFromResponse(accessTokenResponse.successBody!)
|
|
327
|
-
.build();
|
|
328
|
-
|
|
329
|
-
//TS2322: Type '(args: ProofOfPossessionCallbackArgs) => Promise<string>'
|
|
330
|
-
// is not assignable to type 'ProofOfPossessionCallback'.
|
|
331
|
-
// Types of parameters 'args' and 'args' are incompatible.
|
|
332
|
-
// Property 'kid' is missing in type '{ header: unknown; payload: unknown; }' but required in type 'ProofOfPossessionCallbackArgs'.
|
|
333
|
-
const proof: ProofOfPossession = await ProofOfPossessionBuilder.fromJwt({
|
|
334
|
-
jwt: jwtDid,
|
|
335
|
-
callbacks: {
|
|
336
|
-
signCallback: proofOfPossessionCallbackFunction,
|
|
337
|
-
},
|
|
338
|
-
version: OpenId4VCIVersion.VER_1_0_11,
|
|
339
|
-
})
|
|
340
|
-
.withEndpointMetadata({
|
|
341
|
-
issuer: 'https://issuer.research.identiproof.io',
|
|
342
|
-
credential_endpoint: 'https://issuer.research.identiproof.io/credential',
|
|
343
|
-
token_endpoint: 'https://issuer.research.identiproof.io/token',
|
|
344
|
-
})
|
|
345
|
-
.withKid('did:example:ebfeb1f712ebc6f1c276e12ec21/keys/1')
|
|
346
|
-
.build();
|
|
347
|
-
const credResponse = await credReqClient.acquireCredentialsUsingProof({
|
|
348
|
-
proofInput: proof,
|
|
349
|
-
credentialTypes: credentialOffer.original_credential_offer.credential_configuration_ids[0],
|
|
350
|
-
});
|
|
351
|
-
expect(credResponse.successBody?.credential).toEqual(mockedVC);
|
|
352
|
-
},
|
|
353
|
-
UNIT_TEST_TIMEOUT,
|
|
354
|
-
);
|
|
355
|
-
|
|
356
|
-
it(
|
|
357
|
-
'succeed with a full flow with a not-did-kid without the client v1_0_13',
|
|
358
|
-
async () => {
|
|
359
|
-
/* Convert the URI into an object */
|
|
360
|
-
const credentialOffer: CredentialOfferRequestWithBaseUrl = await CredentialOfferClient.fromURI(INITIATE_QR_V1_0_13);
|
|
361
|
-
const preAuthorizedCode = 'oaKazRN8I0IbtZ0C7JuMn5';
|
|
362
|
-
expect(credentialOffer.baseUrl).toEqual('openid-credential-offer://');
|
|
363
|
-
expect((credentialOffer.credential_offer as CredentialOfferPayloadV1_0_13).credential_configuration_ids).toEqual(['OpenBadgeCredentialUrl']);
|
|
364
|
-
expect(credentialOffer.original_credential_offer.grants).toEqual({
|
|
365
|
-
'urn:ietf:params:oauth:grant-type:pre-authorized_code': {
|
|
366
|
-
'pre-authorized_code': preAuthorizedCode,
|
|
367
|
-
tx_code: {
|
|
368
|
-
input_mode: 'text',
|
|
369
|
-
description: 'Please enter the serial number of your physical drivers license',
|
|
370
|
-
length: preAuthorizedCode.length,
|
|
296
|
+
expect(credentialOffer.original_credential_offer).toEqual({
|
|
297
|
+
credential_configuration_ids: ['OpenBadgeCredentialUrl'],
|
|
298
|
+
credential_issuer: ISSUER_URL,
|
|
299
|
+
grants: {
|
|
300
|
+
'urn:ietf:params:oauth:grant-type:pre-authorized_code': {
|
|
301
|
+
'pre-authorized_code': "oaKazRN8I0IbtZ0C7JuMn5",
|
|
302
|
+
tx_code: {
|
|
303
|
+
description: 'Please enter the serial number of your physical drivers license',
|
|
304
|
+
input_mode: 'text',
|
|
305
|
+
length: 22,
|
|
306
|
+
},
|
|
371
307
|
},
|
|
372
|
-
}
|
|
308
|
+
}
|
|
373
309
|
});
|
|
374
310
|
|
|
375
311
|
nock(ISSUER_URL)
|
|
@@ -402,7 +338,7 @@ describe('OID4VCI-Client should', () => {
|
|
|
402
338
|
callbacks: {
|
|
403
339
|
signCallback: proofOfPossessionCallbackFunction,
|
|
404
340
|
},
|
|
405
|
-
version: OpenId4VCIVersion.
|
|
341
|
+
version: OpenId4VCIVersion.VER_1_0_13,
|
|
406
342
|
})
|
|
407
343
|
.withEndpointMetadata({
|
|
408
344
|
issuer: 'https://issuer.research.identiproof.io',
|
|
@@ -411,143 +347,9 @@ describe('OID4VCI-Client should', () => {
|
|
|
411
347
|
})
|
|
412
348
|
.withKid('ebfeb1f712ebc6f1c276e12ec21/keys/1')
|
|
413
349
|
.build();
|
|
414
|
-
const credResponse = await credReqClient.acquireCredentialsUsingProof({
|
|
415
|
-
proofInput: proof,
|
|
416
|
-
credentialTypes: credentialOffer.original_credential_offer.credential_configuration_ids,
|
|
417
|
-
});
|
|
350
|
+
const credResponse = await credReqClient.acquireCredentialsUsingProof({ proofInput: proof, credentialIdentifier: 'OpenBadgeCredentialUrl'});
|
|
418
351
|
expect(credResponse.successBody?.credential).toEqual(mockedVC);
|
|
419
352
|
},
|
|
420
353
|
UNIT_TEST_TIMEOUT,
|
|
421
354
|
);
|
|
422
355
|
});
|
|
423
|
-
|
|
424
|
-
describe('OIDVCI-Client for v1_0_13 should', () => {
|
|
425
|
-
const INITIATE_QR_V1_0_13_CREDENCO =
|
|
426
|
-
'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';
|
|
427
|
-
|
|
428
|
-
const mockedCredentialOffer = {
|
|
429
|
-
credential_issuer: 'https://mijnkvk.acc.credenco.com',
|
|
430
|
-
credential_configuration_ids: ['BevoegdheidUittreksel_jwt_vc_json'],
|
|
431
|
-
grants: {
|
|
432
|
-
authorization_code: {
|
|
433
|
-
issuer_state: '32fc4ebf-9e31-4149-9877-e3c0b602d559',
|
|
434
|
-
},
|
|
435
|
-
'urn:ietf:params:oauth:grant-type:pre-authorized_code': {
|
|
436
|
-
'pre-authorized_code':
|
|
437
|
-
'eyJhbGciOiJFZERTQSJ9.eyJzdWIiOiIzMmZjNGViZi05ZTMxLTQxNDktOTg3Ny1lM2MwYjYwMmQ1NTkiLCJpc3MiOiJodHRwczovL21pam5rdmsuYWNjLmNyZWRlbmNvLmNvbSIsImF1ZCI6IlRPS0VOIn0.754aiQ87O0vHYSpRvPqAS9cLOgf-pewdeXbpLziRwsxEp9mENfaXpY62muYpzOaWcYmTOydkzhFul-NDYXJZCA',
|
|
438
|
-
},
|
|
439
|
-
},
|
|
440
|
-
};
|
|
441
|
-
|
|
442
|
-
beforeEach(() => {
|
|
443
|
-
// Mock the HTTP GET request to the credential offer URI
|
|
444
|
-
nock('https://mijnkvk.acc.credenco.com')
|
|
445
|
-
.get('/openid4vc/credentialOffer?id=32fc4ebf-9e31-4149-9877-e3c0b602d559')
|
|
446
|
-
.reply(200, mockedCredentialOffer)
|
|
447
|
-
.persist(); // Use .persist() if you want the mock to remain active for multiple tests
|
|
448
|
-
});
|
|
449
|
-
|
|
450
|
-
afterEach(() => {
|
|
451
|
-
// Clean up all mocks
|
|
452
|
-
nock.cleanAll();
|
|
453
|
-
});
|
|
454
|
-
|
|
455
|
-
/*function succeedWithAFullFlowWithClientSetup() {
|
|
456
|
-
nock(IDENTIPROOF_ISSUER_URL).get('/.well-known/openid-credential-issuer').reply(200, JSON.stringify(IDENTIPROOF_OID4VCI_METADATA));
|
|
457
|
-
nock(IDENTIPROOF_AS_URL).get('/.well-known/oauth-authorization-server').reply(200, JSON.stringify(IDENTIPROOF_AS_METADATA));
|
|
458
|
-
nock(IDENTIPROOF_AS_URL).get(WellKnownEndpoints.OPENID_CONFIGURATION).reply(404, {});
|
|
459
|
-
nock(IDENTIPROOF_AS_URL)
|
|
460
|
-
.post(/oauth2\/token.*!/)
|
|
461
|
-
.reply(200, JSON.stringify(mockedAccessTokenResponse));
|
|
462
|
-
nock(ISSUER_URL)
|
|
463
|
-
.post(/credential/)
|
|
464
|
-
.reply(200, {
|
|
465
|
-
format: 'jwt-vc',
|
|
466
|
-
credential: mockedVC,
|
|
467
|
-
});
|
|
468
|
-
}*/
|
|
469
|
-
|
|
470
|
-
it('should successfully resolve the credential offer URI', async () => {
|
|
471
|
-
const uri = 'https://mijnkvk.acc.credenco.com/openid4vc/credentialOffer?id=32fc4ebf-9e31-4149-9877-e3c0b602d559';
|
|
472
|
-
|
|
473
|
-
const credentialOffer = await resolveCredentialOfferURI(uri);
|
|
474
|
-
|
|
475
|
-
expect(credentialOffer).toEqual(mockedCredentialOffer);
|
|
476
|
-
});
|
|
477
|
-
|
|
478
|
-
// TODO: ksadjad remove the skipped test
|
|
479
|
-
it.skip(
|
|
480
|
-
'succeed credenco with a full flow without the client v1_0_13',
|
|
481
|
-
async () => {
|
|
482
|
-
/* Convert the URI into an object */
|
|
483
|
-
// 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
|
|
484
|
-
const credentialOffer: CredentialOfferRequestWithBaseUrl = await CredentialOfferClient.fromURI(INITIATE_QR_V1_0_13_CREDENCO);
|
|
485
|
-
/**
|
|
486
|
-
* {"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"}}}
|
|
487
|
-
*/
|
|
488
|
-
const preAuthorizedCode =
|
|
489
|
-
'eyJhbGciOiJFZERTQSJ9.eyJzdWIiOiIzMmZjNGViZi05ZTMxLTQxNDktOTg3Ny1lM2MwYjYwMmQ1NTkiLCJpc3MiOiJodHRwczovL21pam5rdmsuYWNjLmNyZWRlbmNvLmNvbSIsImF1ZCI6IlRPS0VOIn0.754aiQ87O0vHYSpRvPqAS9cLOgf-pewdeXbpLziRwsxEp9mENfaXpY62muYpzOaWcYmTOydkzhFul-NDYXJZCA';
|
|
490
|
-
expect(credentialOffer.baseUrl).toEqual('openid-credential-offer://mijnkvk.acc.credenco.com/');
|
|
491
|
-
expect((credentialOffer.credential_offer as CredentialOfferPayloadV1_0_13).credential_configuration_ids).toEqual([
|
|
492
|
-
'BevoegdheidUittreksel_jwt_vc_json',
|
|
493
|
-
]);
|
|
494
|
-
expect(credentialOffer.original_credential_offer.grants).toEqual({
|
|
495
|
-
authorization_code: {
|
|
496
|
-
issuer_state: '32fc4ebf-9e31-4149-9877-e3c0b602d559',
|
|
497
|
-
},
|
|
498
|
-
'urn:ietf:params:oauth:grant-type:pre-authorized_code': {
|
|
499
|
-
'pre-authorized_code': preAuthorizedCode,
|
|
500
|
-
},
|
|
501
|
-
});
|
|
502
|
-
|
|
503
|
-
/*nock(ISSUER_URL)
|
|
504
|
-
.post(/token.*!/)
|
|
505
|
-
.reply(200, JSON.stringify(mockedAccessTokenResponse));*/
|
|
506
|
-
|
|
507
|
-
/* The actual access token calls */
|
|
508
|
-
const accessTokenClient: AccessTokenClient = new AccessTokenClient();
|
|
509
|
-
const accessTokenResponse = await accessTokenClient.acquireAccessToken({
|
|
510
|
-
credentialOffer: credentialOffer,
|
|
511
|
-
pin: preAuthorizedCode /*, metadata: {}*/,
|
|
512
|
-
});
|
|
513
|
-
expect(accessTokenResponse.successBody).toEqual({});
|
|
514
|
-
/*// Get the credential
|
|
515
|
-
nock(ISSUER_URL)
|
|
516
|
-
.post(/credential/)
|
|
517
|
-
.reply(200, {
|
|
518
|
-
format: 'jwt-vc',
|
|
519
|
-
credential: mockedVC,
|
|
520
|
-
});
|
|
521
|
-
const credReqClient = CredentialRequestClientBuilder.fromCredentialOffer({ credentialOffer: credentialOffer })
|
|
522
|
-
.withFormat('jwt_vc')
|
|
523
|
-
|
|
524
|
-
.withTokenFromResponse(accessTokenResponse.successBody!)
|
|
525
|
-
.build();
|
|
526
|
-
|
|
527
|
-
//TS2322: Type '(args: ProofOfPossessionCallbackArgs) => Promise<string>'
|
|
528
|
-
// is not assignable to type 'ProofOfPossessionCallback'.
|
|
529
|
-
// Types of parameters 'args' and 'args' are incompatible.
|
|
530
|
-
// Property 'kid' is missing in type '{ header: unknown; payload: unknown; }' but required in type 'ProofOfPossessionCallbackArgs'.
|
|
531
|
-
const proof: ProofOfPossession = await ProofOfPossessionBuilder.fromJwt({
|
|
532
|
-
jwt,
|
|
533
|
-
callbacks: {
|
|
534
|
-
signCallback: proofOfPossessionCallbackFunction,
|
|
535
|
-
},
|
|
536
|
-
version: OpenId4VCIVersion.VER_1_0_11,
|
|
537
|
-
})
|
|
538
|
-
.withEndpointMetadata({
|
|
539
|
-
issuer: 'https://issuer.research.identiproof.io',
|
|
540
|
-
credential_endpoint: 'https://issuer.research.identiproof.io/credential',
|
|
541
|
-
token_endpoint: 'https://issuer.research.identiproof.io/token',
|
|
542
|
-
})
|
|
543
|
-
.withKid('did:example:ebfeb1f712ebc6f1c276e12ec21/keys/1')
|
|
544
|
-
.build();
|
|
545
|
-
const credResponse = await credReqClient.acquireCredentialsUsingProof({
|
|
546
|
-
proofInput: proof,
|
|
547
|
-
credentialTypes: credentialOffer.original_credential_offer.credential_configuration_ids,
|
|
548
|
-
});
|
|
549
|
-
expect(credResponse.successBody?.credential).toEqual(mockedVC);*/
|
|
550
|
-
},
|
|
551
|
-
UNIT_TEST_TIMEOUT,
|
|
552
|
-
);
|
|
553
|
-
});
|
|
@@ -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',
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sphereon/oid4vci-client",
|
|
3
|
-
"version": "0.12.1-unstable.
|
|
3
|
+
"version": "0.12.1-unstable.3+5439a02",
|
|
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.12.1-unstable.
|
|
18
|
+
"@sphereon/oid4vci-common": "0.12.1-unstable.3+5439a02",
|
|
19
19
|
"@sphereon/ssi-types": "0.25.1-unstable.87",
|
|
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": "5439a02483c16666629912152dd3618536f51bf2"
|
|
73
73
|
}
|