@sphereon/oid4vci-client 0.2.0 → 0.4.1-unstable.247

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 (116) hide show
  1. package/LICENSE +201 -201
  2. package/README.md +494 -371
  3. package/dist/AccessTokenClient.d.ts +30 -0
  4. package/dist/AccessTokenClient.d.ts.map +1 -0
  5. package/dist/AccessTokenClient.js +226 -0
  6. package/dist/AccessTokenClient.js.map +1 -0
  7. package/dist/AuthorizationDetailsBuilder.d.ts +11 -0
  8. package/dist/AuthorizationDetailsBuilder.d.ts.map +1 -0
  9. package/dist/AuthorizationDetailsBuilder.js +44 -0
  10. package/dist/AuthorizationDetailsBuilder.js.map +1 -0
  11. package/dist/CredentialOffer.d.ts +6 -0
  12. package/dist/CredentialOffer.d.ts.map +1 -0
  13. package/dist/CredentialOffer.js +49 -0
  14. package/dist/CredentialOffer.js.map +1 -0
  15. package/dist/CredentialRequestClient.d.ts +29 -0
  16. package/dist/CredentialRequestClient.d.ts.map +1 -0
  17. package/dist/CredentialRequestClient.js +63 -0
  18. package/dist/CredentialRequestClient.js.map +1 -0
  19. package/dist/CredentialRequestClientBuilderV1_0_09.d.ts +29 -0
  20. package/dist/CredentialRequestClientBuilderV1_0_09.d.ts.map +1 -0
  21. package/dist/CredentialRequestClientBuilderV1_0_09.js +63 -0
  22. package/dist/CredentialRequestClientBuilderV1_0_09.js.map +1 -0
  23. package/dist/{main/lib/MetadataClient.d.ts → MetadataClient.d.ts} +39 -38
  24. package/dist/MetadataClient.d.ts.map +1 -0
  25. package/dist/MetadataClient.js +148 -0
  26. package/dist/MetadataClient.js.map +1 -0
  27. package/dist/OpenID4VCIClient.d.ts +72 -0
  28. package/dist/OpenID4VCIClient.d.ts.map +1 -0
  29. package/dist/OpenID4VCIClient.js +361 -0
  30. package/dist/OpenID4VCIClient.js.map +1 -0
  31. package/dist/ProofOfPossessionBuilder.d.ts +35 -0
  32. package/dist/ProofOfPossessionBuilder.d.ts.map +1 -0
  33. package/dist/ProofOfPossessionBuilder.js +120 -0
  34. package/dist/ProofOfPossessionBuilder.js.map +1 -0
  35. package/dist/{main/lib/functions → functions}/Encoding.d.ts +20 -17
  36. package/dist/functions/Encoding.d.ts.map +1 -0
  37. package/dist/functions/Encoding.js +144 -0
  38. package/dist/functions/Encoding.js.map +1 -0
  39. package/dist/functions/HttpUtils.d.ts +24 -0
  40. package/dist/functions/HttpUtils.d.ts.map +1 -0
  41. package/dist/functions/HttpUtils.js +93 -0
  42. package/dist/functions/HttpUtils.js.map +1 -0
  43. package/dist/functions/ProofUtil.d.ts +29 -0
  44. package/dist/functions/ProofUtil.d.ts.map +1 -0
  45. package/dist/functions/ProofUtil.js +103 -0
  46. package/dist/functions/ProofUtil.js.map +1 -0
  47. package/dist/functions/index.d.ts +4 -0
  48. package/dist/functions/index.d.ts.map +1 -0
  49. package/dist/{main/lib/functions → functions}/index.js +20 -20
  50. package/dist/functions/index.js.map +1 -0
  51. package/dist/index.d.ts +9 -0
  52. package/dist/index.d.ts.map +1 -0
  53. package/dist/{main/lib/index.js → index.js} +25 -24
  54. package/dist/index.js.map +1 -0
  55. package/lib/AccessTokenClient.ts +270 -0
  56. package/lib/AuthorizationDetailsBuilder.ts +46 -0
  57. package/lib/CredentialOffer.ts +55 -0
  58. package/lib/CredentialRequestClient.ts +77 -0
  59. package/lib/CredentialRequestClientBuilderV1_0_09.ts +99 -0
  60. package/lib/MetadataClient.ts +147 -0
  61. package/lib/OpenID4VCIClient.ts +477 -0
  62. package/lib/ProofOfPossessionBuilder.ts +156 -0
  63. package/lib/__tests__/AccessTokenClient.spec.ts +221 -0
  64. package/lib/__tests__/AuthorizationDetailsBuilder.spec.ts +65 -0
  65. package/lib/__tests__/AuthzFlowType.spec.ts +39 -0
  66. package/lib/__tests__/CredentialRequestClient.spec.ts +261 -0
  67. package/lib/__tests__/CredentialRequestClientBuilder.spec.ts +103 -0
  68. package/lib/__tests__/HttpUtils.spec.ts +37 -0
  69. package/lib/__tests__/IT.spec.ts +155 -0
  70. package/lib/__tests__/IssuanceInitiation.spec.ts +37 -0
  71. package/lib/__tests__/JsonURIConversions.spec.ts +86 -0
  72. package/lib/__tests__/MetadataClient.spec.ts +198 -0
  73. package/lib/__tests__/MetadataMocks.ts +428 -0
  74. package/lib/__tests__/OpenID4VCIClient.spec.ts +166 -0
  75. package/lib/__tests__/OpenID4VCIClientPAR.spec.ts +112 -0
  76. package/lib/__tests__/ProofOfPossessionBuilder.spec.ts +109 -0
  77. package/lib/__tests__/data/VciDataFixtures.ts +744 -0
  78. package/lib/functions/Encoding.ts +138 -0
  79. package/lib/functions/HttpUtils.ts +106 -0
  80. package/lib/functions/ProofUtil.ts +128 -0
  81. package/{dist/main/lib/functions/index.d.ts → lib/functions/index.ts} +3 -3
  82. package/lib/index.ts +8 -0
  83. package/package.json +68 -71
  84. package/CHANGELOG.md +0 -21
  85. package/dist/main/index.d.ts +0 -1
  86. package/dist/main/index.js +0 -18
  87. package/dist/main/lib/AccessTokenClient.d.ts +0 -20
  88. package/dist/main/lib/AccessTokenClient.js +0 -141
  89. package/dist/main/lib/CredentialRequestClient.d.ts +0 -31
  90. package/dist/main/lib/CredentialRequestClient.js +0 -66
  91. package/dist/main/lib/CredentialRequestClientBuilder.d.ts +0 -21
  92. package/dist/main/lib/CredentialRequestClientBuilder.js +0 -56
  93. package/dist/main/lib/IssuanceInitiation.d.ts +0 -5
  94. package/dist/main/lib/IssuanceInitiation.js +0 -29
  95. package/dist/main/lib/MetadataClient.js +0 -127
  96. package/dist/main/lib/functions/Encoding.js +0 -138
  97. package/dist/main/lib/functions/HttpUtils.d.ts +0 -17
  98. package/dist/main/lib/functions/HttpUtils.js +0 -133
  99. package/dist/main/lib/functions/ProofUtil.d.ts +0 -9
  100. package/dist/main/lib/functions/ProofUtil.js +0 -76
  101. package/dist/main/lib/index.d.ts +0 -7
  102. package/dist/main/lib/types/Authorization.types.d.ts +0 -66
  103. package/dist/main/lib/types/Authorization.types.js +0 -35
  104. package/dist/main/lib/types/CredentialIssuance.types.d.ts +0 -88
  105. package/dist/main/lib/types/CredentialIssuance.types.js +0 -8
  106. package/dist/main/lib/types/Generic.types.d.ts +0 -19
  107. package/dist/main/lib/types/Generic.types.js +0 -11
  108. package/dist/main/lib/types/OAuth2ASMetadata.d.ts +0 -37
  109. package/dist/main/lib/types/OAuth2ASMetadata.js +0 -3
  110. package/dist/main/lib/types/OID4VCIServerMetadata.d.ts +0 -65
  111. package/dist/main/lib/types/OID4VCIServerMetadata.js +0 -3
  112. package/dist/main/lib/types/Oidc4vciErrors.d.ts +0 -3
  113. package/dist/main/lib/types/Oidc4vciErrors.js +0 -7
  114. package/dist/main/lib/types/index.d.ts +0 -6
  115. package/dist/main/lib/types/index.js +0 -23
  116. package/dist/main/tsconfig.build.tsbuildinfo +0 -1
@@ -0,0 +1,112 @@
1
+ import { AuthzFlowType, CodeChallengeMethod, Oauth2ASWithOID4VCIMetadata } from '@sphereon/oid4vci-common';
2
+ import nock from 'nock';
3
+
4
+ import { OpenID4VCIClient } from '../OpenID4VCIClient';
5
+
6
+ const MOCK_URL = 'https://server.example.com/';
7
+ describe('OpenID4VCIClient', () => {
8
+ let client: OpenID4VCIClient;
9
+
10
+ beforeEach(async () => {
11
+ nock(MOCK_URL).get(/.*/).reply(200, {});
12
+ nock(`${MOCK_URL}`).post('/v1/auth/par').reply(201, { request_uri: 'test_uri', expires_in: 90 });
13
+ client = await OpenID4VCIClient.fromURI({
14
+ uri: 'openid-initiate-issuance://?issuer=https://server.example.com&credential_type=TestCredential',
15
+ flowType: AuthzFlowType.AUTHORIZATION_CODE_FLOW,
16
+ });
17
+ });
18
+
19
+ afterEach(() => {
20
+ nock.cleanAll();
21
+ });
22
+
23
+ it('should successfully retrieve the authorization code using PAR', async () => {
24
+ (client.endpointMetadata.issuerMetadata! as Oauth2ASWithOID4VCIMetadata).pushed_authorization_request_endpoint = `${MOCK_URL}v1/auth/par`;
25
+ const actual = await client.acquirePushedAuthorizationRequestURI({
26
+ clientId: 'test-client',
27
+ codeChallengeMethod: CodeChallengeMethod.SHA256,
28
+ codeChallenge: 'mE2kPHmIprOqtkaYmESWj35yz-PB5vzdiSu0tAZ8sqs',
29
+ scope: 'openid TestCredential',
30
+ redirectUri: 'http://localhost:8881/cb',
31
+ });
32
+ expect(actual.successBody).toEqual({ request_uri: 'test_uri', expires_in: 90 });
33
+ });
34
+
35
+ it('should fail when pushed_authorization_request_endpoint is not present', async () => {
36
+ await expect(() =>
37
+ client.acquirePushedAuthorizationRequestURI({
38
+ clientId: 'test-client',
39
+ codeChallengeMethod: CodeChallengeMethod.SHA256,
40
+ codeChallenge: 'mE2kPHmIprOqtkaYmESWj35yz-PB5vzdiSu0tAZ8sqs',
41
+ scope: 'openid TestCredential',
42
+ redirectUri: 'http://localhost:8881/cb',
43
+ })
44
+ ).rejects.toThrow(Error('Server metadata does not contain pushed authorization request endpoint'));
45
+ });
46
+
47
+ it('should fail when authorization_details and scope are not present', async () => {
48
+ await expect(() =>
49
+ client.acquirePushedAuthorizationRequestURI({
50
+ clientId: 'test-client',
51
+ codeChallengeMethod: CodeChallengeMethod.SHA256,
52
+ codeChallenge: 'mE2kPHmIprOqtkaYmESWj35yz-PB5vzdiSu0tAZ8sqs',
53
+ redirectUri: 'http://localhost:8881/cb',
54
+ })
55
+ ).rejects.toThrow(Error('Please provide a scope or authorization_details'));
56
+ });
57
+
58
+ it('should not fail when only authorization_details is present', async () => {
59
+ (client.endpointMetadata.issuerMetadata! as Oauth2ASWithOID4VCIMetadata).pushed_authorization_request_endpoint = `${MOCK_URL}v1/auth/par`;
60
+ const actual = await client.acquirePushedAuthorizationRequestURI({
61
+ clientId: 'test-client',
62
+ codeChallengeMethod: CodeChallengeMethod.SHA256,
63
+ codeChallenge: 'mE2kPHmIprOqtkaYmESWj35yz-PB5vzdiSu0tAZ8sqs',
64
+ authorizationDetails: [
65
+ {
66
+ type: 'openid_credential',
67
+ format: 'ldp_vc',
68
+ credential_definition: {
69
+ '@context': ['https://www.w3.org/2018/credentials/v1', 'https://www.w3.org/2018/credentials/examples/v1'],
70
+ types: ['VerifiableCredential', 'UniversityDegreeCredential'],
71
+ },
72
+ },
73
+ ],
74
+ redirectUri: 'http://localhost:8881/cb',
75
+ });
76
+ expect(actual.successBody).toEqual({ request_uri: 'test_uri', expires_in: 90 });
77
+ });
78
+
79
+ it('should not fail when only scope is present', async () => {
80
+ (client.endpointMetadata.issuerMetadata! as Oauth2ASWithOID4VCIMetadata).pushed_authorization_request_endpoint = `${MOCK_URL}v1/auth/par`;
81
+ const actual = await client.acquirePushedAuthorizationRequestURI({
82
+ clientId: 'test-client',
83
+ codeChallengeMethod: CodeChallengeMethod.SHA256,
84
+ codeChallenge: 'mE2kPHmIprOqtkaYmESWj35yz-PB5vzdiSu0tAZ8sqs',
85
+ scope: 'openid TestCredential',
86
+ redirectUri: 'http://localhost:8881/cb',
87
+ });
88
+ expect(actual.successBody).toEqual({ request_uri: 'test_uri', expires_in: 90 });
89
+ });
90
+
91
+ it('should not fail when both authorization_details and scope are present', async () => {
92
+ (client.endpointMetadata.issuerMetadata! as Oauth2ASWithOID4VCIMetadata).pushed_authorization_request_endpoint = `${MOCK_URL}v1/auth/par`;
93
+ const actual = await client.acquirePushedAuthorizationRequestURI({
94
+ clientId: 'test-client',
95
+ codeChallengeMethod: CodeChallengeMethod.SHA256,
96
+ codeChallenge: 'mE2kPHmIprOqtkaYmESWj35yz-PB5vzdiSu0tAZ8sqs',
97
+ authorizationDetails: [
98
+ {
99
+ type: 'openid_credential',
100
+ format: 'ldp_vc',
101
+ credential_definition: {
102
+ '@context': ['https://www.w3.org/2018/credentials/v1', 'https://www.w3.org/2018/credentials/examples/v1'],
103
+ types: ['VerifiableCredential', 'UniversityDegreeCredential'],
104
+ },
105
+ },
106
+ ],
107
+ scope: 'openid TestCredential',
108
+ redirectUri: 'http://localhost:8881/cb',
109
+ });
110
+ expect(actual.successBody).toEqual({ request_uri: 'test_uri', expires_in: 90 });
111
+ });
112
+ });
@@ -0,0 +1,109 @@
1
+ import { KeyObject } from 'crypto';
2
+
3
+ import { Alg, JWS_NOT_VALID, Jwt, NO_JWT_PROVIDED, PROOF_CANT_BE_CONSTRUCTED, ProofOfPossession, Typ } from '@sphereon/oid4vci-common';
4
+ import * as jose from 'jose';
5
+
6
+ import { ProofOfPossessionBuilder } from '..';
7
+
8
+ import { IDENTIPROOF_ISSUER_URL } from './MetadataMocks';
9
+
10
+ const jwt: Jwt = {
11
+ header: { alg: Alg.ES256, kid: 'did:example:ebfeb1f712ebc6f1c276e12ec21/keys/1', typ: Typ.JWT },
12
+ payload: { iss: 'sphereon:wallet', nonce: 'tZignsnFbp', jti: 'tZignsnFbp223', aud: IDENTIPROOF_ISSUER_URL, iat: Date.now() },
13
+ };
14
+
15
+ const kid = 'did:example:ebfeb1f712ebc6f1c276e12ec21/keys/1';
16
+
17
+ let keypair: KeyPair;
18
+
19
+ async function proofOfPossessionCallbackFunction(args: Jwt, kid?: string): Promise<string> {
20
+ if (!args.payload.aud) {
21
+ throw Error('aud required');
22
+ } else if (!kid) {
23
+ throw Error('kid required');
24
+ }
25
+ return await new jose.SignJWT({ ...args.payload })
26
+ .setProtectedHeader({ alg: 'ES256' })
27
+ .setIssuedAt(args.payload.iat)
28
+ .setIssuer(kid)
29
+ .setAudience(args.payload.aud)
30
+ .setExpirationTime('2h')
31
+ .sign(keypair.privateKey);
32
+ }
33
+
34
+ interface KeyPair {
35
+ publicKey: KeyObject;
36
+ privateKey: KeyObject;
37
+ }
38
+
39
+ beforeAll(async () => {
40
+ const { privateKey, publicKey } = await jose.generateKeyPair('ES256');
41
+ keypair = { publicKey: publicKey as KeyObject, privateKey: privateKey as KeyObject };
42
+ });
43
+
44
+ describe('ProofOfPossession Builder ', () => {
45
+ it('should fail without supplied proof or callbacks', async function () {
46
+ await expect(
47
+ ProofOfPossessionBuilder.fromProof(undefined as never)
48
+ .withIssuer(IDENTIPROOF_ISSUER_URL)
49
+ .withClientId('sphereon:wallet')
50
+ .withKid(kid)
51
+ .build()
52
+ ).rejects.toThrow(Error(PROOF_CANT_BE_CONSTRUCTED));
53
+ });
54
+
55
+ it('should fail wit undefined jwt supplied', async function () {
56
+ await expect(() =>
57
+ ProofOfPossessionBuilder.fromJwt({ jwt, callbacks: { signCallback: proofOfPossessionCallbackFunction } })
58
+ .withJwt(undefined as never)
59
+ .withIssuer(IDENTIPROOF_ISSUER_URL)
60
+ .withClientId('sphereon:wallet')
61
+ .withKid(kid)
62
+ .build()
63
+ ).toThrow(Error(NO_JWT_PROVIDED));
64
+ });
65
+
66
+ it('should build a proof with all required params present', async function () {
67
+ const proof: ProofOfPossession = await ProofOfPossessionBuilder.fromJwt({
68
+ jwt,
69
+ callbacks: {
70
+ signCallback: proofOfPossessionCallbackFunction,
71
+ },
72
+ })
73
+ .withIssuer(IDENTIPROOF_ISSUER_URL)
74
+ .withKid(kid)
75
+ .withClientId('sphereon:wallet')
76
+ .build();
77
+ expect(proof).toBeDefined();
78
+ });
79
+
80
+ it('should fail creating a proof of possession with simple verification', async () => {
81
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
82
+ async function proofOfPossessionCallbackFunction(_args: Jwt, _kid?: string): Promise<string> {
83
+ throw new Error(JWS_NOT_VALID);
84
+ }
85
+
86
+ await expect(
87
+ ProofOfPossessionBuilder.fromJwt({ jwt, callbacks: { signCallback: proofOfPossessionCallbackFunction } })
88
+ .withIssuer(IDENTIPROOF_ISSUER_URL)
89
+ .withClientId('sphereon:wallet')
90
+ .withKid(kid)
91
+ .build()
92
+ ).rejects.toThrow(Error(JWS_NOT_VALID));
93
+ });
94
+
95
+ it('should fail creating a proof of possession without verify callback', async () => {
96
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
97
+ async function proofOfPossessionCallbackFunction(_args: Jwt, _kid?: string): Promise<string> {
98
+ throw new Error(JWS_NOT_VALID);
99
+ }
100
+
101
+ await expect(
102
+ ProofOfPossessionBuilder.fromJwt({ jwt, callbacks: { signCallback: proofOfPossessionCallbackFunction } })
103
+ .withIssuer(IDENTIPROOF_ISSUER_URL)
104
+ .withClientId('sphereon:wallet')
105
+ .withKid(kid)
106
+ .build()
107
+ ).rejects.toThrow(Error(JWS_NOT_VALID));
108
+ });
109
+ });