@sphereon/oid4vci-client 0.2.0 → 0.4.1-next.285

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 (107) 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 +222 -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/CredentialOfferClient.d.ts +10 -0
  12. package/dist/CredentialOfferClient.d.ts.map +1 -0
  13. package/dist/CredentialOfferClient.js +101 -0
  14. package/dist/CredentialOfferClient.js.map +1 -0
  15. package/dist/CredentialRequestClient.d.ts +33 -0
  16. package/dist/CredentialRequestClient.d.ts.map +1 -0
  17. package/dist/CredentialRequestClient.js +118 -0
  18. package/dist/CredentialRequestClient.js.map +1 -0
  19. package/dist/CredentialRequestClientBuilder.d.ts +34 -0
  20. package/dist/CredentialRequestClientBuilder.d.ts.map +1 -0
  21. package/dist/CredentialRequestClientBuilder.js +87 -0
  22. package/dist/CredentialRequestClientBuilder.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 +75 -0
  28. package/dist/OpenID4VCIClient.d.ts.map +1 -0
  29. package/dist/OpenID4VCIClient.js +403 -0
  30. package/dist/OpenID4VCIClient.js.map +1 -0
  31. package/dist/ProofOfPossessionBuilder.d.ts +38 -0
  32. package/dist/ProofOfPossessionBuilder.d.ts.map +1 -0
  33. package/dist/ProofOfPossessionBuilder.js +129 -0
  34. package/dist/ProofOfPossessionBuilder.js.map +1 -0
  35. package/dist/functions/ProofUtil.d.ts +29 -0
  36. package/dist/functions/ProofUtil.d.ts.map +1 -0
  37. package/dist/functions/ProofUtil.js +104 -0
  38. package/dist/functions/ProofUtil.js.map +1 -0
  39. package/dist/functions/index.d.ts +4 -0
  40. package/dist/functions/index.d.ts.map +1 -0
  41. package/dist/{main → functions}/index.js +20 -18
  42. package/dist/functions/index.js.map +1 -0
  43. package/dist/index.d.ts +9 -0
  44. package/dist/index.d.ts.map +1 -0
  45. package/dist/{main/lib/index.js → index.js} +25 -24
  46. package/dist/index.js.map +1 -0
  47. package/lib/AccessTokenClient.ts +249 -0
  48. package/lib/AuthorizationDetailsBuilder.ts +46 -0
  49. package/lib/CredentialOfferClient.ts +108 -0
  50. package/lib/CredentialRequestClient.ts +137 -0
  51. package/lib/CredentialRequestClientBuilder.ts +110 -0
  52. package/lib/MetadataClient.ts +147 -0
  53. package/lib/OpenID4VCIClient.ts +523 -0
  54. package/lib/ProofOfPossessionBuilder.ts +181 -0
  55. package/lib/__tests__/AccessTokenClient.spec.ts +225 -0
  56. package/lib/__tests__/AuthorizationDetailsBuilder.spec.ts +65 -0
  57. package/lib/__tests__/AuthzFlowType.spec.ts +39 -0
  58. package/lib/__tests__/CredentialRequestClient.spec.ts +291 -0
  59. package/lib/__tests__/CredentialRequestClientBuilder.spec.ts +121 -0
  60. package/lib/__tests__/HttpUtils.spec.ts +37 -0
  61. package/lib/__tests__/IT.spec.ts +173 -0
  62. package/lib/__tests__/IssuanceInitiation.spec.ts +48 -0
  63. package/lib/__tests__/JsonURIConversions.spec.ts +146 -0
  64. package/lib/__tests__/MetadataClient.spec.ts +203 -0
  65. package/lib/__tests__/MetadataMocks.ts +444 -0
  66. package/lib/__tests__/OpenID4VCIClient.spec.ts +166 -0
  67. package/lib/__tests__/OpenID4VCIClientPAR.spec.ts +112 -0
  68. package/lib/__tests__/ProofOfPossessionBuilder.spec.ts +110 -0
  69. package/lib/__tests__/data/VciDataFixtures.ts +744 -0
  70. package/lib/functions/ProofUtil.ts +120 -0
  71. package/lib/functions/index.ts +3 -0
  72. package/{dist/main/lib/index.d.ts → lib/index.ts} +8 -7
  73. package/package.json +68 -71
  74. package/CHANGELOG.md +0 -21
  75. package/dist/main/index.d.ts +0 -1
  76. package/dist/main/lib/AccessTokenClient.d.ts +0 -20
  77. package/dist/main/lib/AccessTokenClient.js +0 -141
  78. package/dist/main/lib/CredentialRequestClient.d.ts +0 -31
  79. package/dist/main/lib/CredentialRequestClient.js +0 -66
  80. package/dist/main/lib/CredentialRequestClientBuilder.d.ts +0 -21
  81. package/dist/main/lib/CredentialRequestClientBuilder.js +0 -56
  82. package/dist/main/lib/IssuanceInitiation.d.ts +0 -5
  83. package/dist/main/lib/IssuanceInitiation.js +0 -29
  84. package/dist/main/lib/MetadataClient.js +0 -127
  85. package/dist/main/lib/functions/Encoding.d.ts +0 -17
  86. package/dist/main/lib/functions/Encoding.js +0 -138
  87. package/dist/main/lib/functions/HttpUtils.d.ts +0 -17
  88. package/dist/main/lib/functions/HttpUtils.js +0 -133
  89. package/dist/main/lib/functions/ProofUtil.d.ts +0 -9
  90. package/dist/main/lib/functions/ProofUtil.js +0 -76
  91. package/dist/main/lib/functions/index.d.ts +0 -3
  92. package/dist/main/lib/functions/index.js +0 -20
  93. package/dist/main/lib/types/Authorization.types.d.ts +0 -66
  94. package/dist/main/lib/types/Authorization.types.js +0 -35
  95. package/dist/main/lib/types/CredentialIssuance.types.d.ts +0 -88
  96. package/dist/main/lib/types/CredentialIssuance.types.js +0 -8
  97. package/dist/main/lib/types/Generic.types.d.ts +0 -19
  98. package/dist/main/lib/types/Generic.types.js +0 -11
  99. package/dist/main/lib/types/OAuth2ASMetadata.d.ts +0 -37
  100. package/dist/main/lib/types/OAuth2ASMetadata.js +0 -3
  101. package/dist/main/lib/types/OID4VCIServerMetadata.d.ts +0 -65
  102. package/dist/main/lib/types/OID4VCIServerMetadata.js +0 -3
  103. package/dist/main/lib/types/Oidc4vciErrors.d.ts +0 -3
  104. package/dist/main/lib/types/Oidc4vciErrors.js +0 -7
  105. package/dist/main/lib/types/index.d.ts +0 -6
  106. package/dist/main/lib/types/index.js +0 -23
  107. package/dist/main/tsconfig.build.tsbuildinfo +0 -1
@@ -0,0 +1,104 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ var __importDefault = (this && this.__importDefault) || function (mod) {
12
+ return (mod && mod.__esModule) ? mod : { "default": mod };
13
+ };
14
+ Object.defineProperty(exports, "__esModule", { value: true });
15
+ exports.createProofOfPossession = void 0;
16
+ const oid4vci_common_1 = require("@sphereon/oid4vci-common");
17
+ const debug_1 = __importDefault(require("debug"));
18
+ const debug = (0, debug_1.default)('sphereon:openid4vci:token');
19
+ /**
20
+ *
21
+ * - proofOfPossessionCallback: JWTSignerCallback
22
+ * Mandatory if you want to create (sign) ProofOfPossession
23
+ * - proofOfPossessionVerifierCallback?: JWTVerifyCallback
24
+ * If exists, verifies the ProofOfPossession
25
+ * - proofOfPossessionCallbackArgs: ProofOfPossessionCallbackArgs
26
+ * arguments needed for signing ProofOfPossession
27
+ * @param callbacks:
28
+ * - proofOfPossessionCallback: JWTSignerCallback
29
+ * Mandatory to create (sign) ProofOfPossession
30
+ * - proofOfPossessionVerifierCallback?: JWTVerifyCallback
31
+ * If exists, verifies the ProofOfPossession
32
+ * @param jwtProps
33
+ * @param existingJwt
34
+ * - Optional, clientId of the party requesting the credential
35
+ */
36
+ const createProofOfPossession = (callbacks, jwtProps, existingJwt) => __awaiter(void 0, void 0, void 0, function* () {
37
+ if (!callbacks.signCallback) {
38
+ debug(`no jwt signer callback or arguments supplied!`);
39
+ throw new Error(oid4vci_common_1.BAD_PARAMS);
40
+ }
41
+ const signerArgs = createJWT(jwtProps, existingJwt);
42
+ const jwt = yield callbacks.signCallback(signerArgs, signerArgs.header.kid);
43
+ const proof = {
44
+ proof_type: 'jwt',
45
+ jwt,
46
+ };
47
+ try {
48
+ partiallyValidateJWS(jwt);
49
+ if (callbacks.verifyCallback) {
50
+ debug(`Calling supplied verify callback....`);
51
+ yield callbacks.verifyCallback({ jwt, kid: signerArgs.header.kid });
52
+ debug(`Supplied verify callback return success result`);
53
+ }
54
+ }
55
+ catch (_a) {
56
+ debug(`JWS was not valid`);
57
+ throw new Error(oid4vci_common_1.JWS_NOT_VALID);
58
+ }
59
+ debug(`Proof of Possession JWT:\r\n${jwt}`);
60
+ return proof;
61
+ });
62
+ exports.createProofOfPossession = createProofOfPossession;
63
+ const partiallyValidateJWS = (jws) => {
64
+ if (jws.split('.').length !== 3 || !jws.startsWith('ey')) {
65
+ throw new Error(oid4vci_common_1.JWS_NOT_VALID);
66
+ }
67
+ };
68
+ const createJWT = (jwtProps, existingJwt) => {
69
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j;
70
+ const aud = getJwtProperty('aud', true, jwtProps === null || jwtProps === void 0 ? void 0 : jwtProps.issuer, (_a = existingJwt === null || existingJwt === void 0 ? void 0 : existingJwt.payload) === null || _a === void 0 ? void 0 : _a.aud);
71
+ const iss = getJwtProperty('iss', false, jwtProps === null || jwtProps === void 0 ? void 0 : jwtProps.clientId, (_b = existingJwt === null || existingJwt === void 0 ? void 0 : existingJwt.payload) === null || _b === void 0 ? void 0 : _b.iss);
72
+ const jti = getJwtProperty('jti', false, jwtProps === null || jwtProps === void 0 ? void 0 : jwtProps.jti, (_c = existingJwt === null || existingJwt === void 0 ? void 0 : existingJwt.payload) === null || _c === void 0 ? void 0 : _c.jti);
73
+ const typ = getJwtProperty('typ', true, jwtProps === null || jwtProps === void 0 ? void 0 : jwtProps.typ, (_d = existingJwt === null || existingJwt === void 0 ? void 0 : existingJwt.header) === null || _d === void 0 ? void 0 : _d.typ, 'jwt');
74
+ const nonce = getJwtProperty('nonce', false, jwtProps === null || jwtProps === void 0 ? void 0 : jwtProps.nonce, (_e = existingJwt === null || existingJwt === void 0 ? void 0 : existingJwt.payload) === null || _e === void 0 ? void 0 : _e.nonce); // Officially this is required, but some implementations don't have it
75
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
76
+ const alg = getJwtProperty('alg', false, jwtProps === null || jwtProps === void 0 ? void 0 : jwtProps.alg, (_f = existingJwt === null || existingJwt === void 0 ? void 0 : existingJwt.header) === null || _f === void 0 ? void 0 : _f.alg, 'ES256');
77
+ const kid = getJwtProperty('kid', true, jwtProps === null || jwtProps === void 0 ? void 0 : jwtProps.kid, (_g = existingJwt === null || existingJwt === void 0 ? void 0 : existingJwt.header) === null || _g === void 0 ? void 0 : _g.kid);
78
+ const jwt = existingJwt ? existingJwt : {};
79
+ const now = +new Date();
80
+ const jwtPayload = Object.assign(Object.assign({ aud, iat: ((_h = jwt.payload) === null || _h === void 0 ? void 0 : _h.iat) ? jwt.payload.iat : now / 1000 - 60, exp: ((_j = jwt.payload) === null || _j === void 0 ? void 0 : _j.exp) ? jwt.payload.exp : now / 1000 + 10 * 60, nonce }, (iss ? { iss } : {})), (jti ? { jti } : {}));
81
+ const jwtHeader = {
82
+ typ,
83
+ alg,
84
+ kid,
85
+ };
86
+ return {
87
+ payload: Object.assign(Object.assign({}, jwt.payload), jwtPayload),
88
+ header: Object.assign(Object.assign({}, jwt.header), jwtHeader),
89
+ };
90
+ };
91
+ const getJwtProperty = (propertyName, required, option, jwtProperty, defaultValue) => {
92
+ if (option && jwtProperty && option !== jwtProperty) {
93
+ throw Error(`Cannot have a property '${propertyName}' with value '${option}' and different JWT value '${jwtProperty}' at the same time`);
94
+ }
95
+ let result = jwtProperty ? jwtProperty : option;
96
+ if (!result) {
97
+ if (required) {
98
+ throw Error(`No ${propertyName} property provided either in a JWT or as option`);
99
+ }
100
+ result = defaultValue;
101
+ }
102
+ return result;
103
+ };
104
+ //# sourceMappingURL=ProofUtil.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ProofUtil.js","sourceRoot":"","sources":["../../lib/functions/ProofUtil.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ export * from '@sphereon/oid4vci-common/dist/functions/Encoding';
2
+ export * from '@sphereon/oid4vci-common/dist/functions/HttpUtils';
3
+ export * from './ProofUtil';
4
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../lib/functions/index.ts"],"names":[],"mappings":"AAAA,cAAc,kDAAkD,CAAC;AACjE,cAAc,mDAAmD,CAAC;AAClE,cAAc,aAAa,CAAC"}
@@ -1,18 +1,20 @@
1
- "use strict";
2
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
- if (k2 === undefined) k2 = k;
4
- var desc = Object.getOwnPropertyDescriptor(m, k);
5
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
- desc = { enumerable: true, get: function() { return m[k]; } };
7
- }
8
- Object.defineProperty(o, k2, desc);
9
- }) : (function(o, m, k, k2) {
10
- if (k2 === undefined) k2 = k;
11
- o[k2] = m[k];
12
- }));
13
- var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
- for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
- };
16
- Object.defineProperty(exports, "__esModule", { value: true });
17
- __exportStar(require("./lib"), exports);
18
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9pbmRleC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7Ozs7Ozs7O0FBQUEsd0NBQXFCIn0=
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ __exportStar(require("@sphereon/oid4vci-common/dist/functions/Encoding"), exports);
18
+ __exportStar(require("@sphereon/oid4vci-common/dist/functions/HttpUtils"), exports);
19
+ __exportStar(require("./ProofUtil"), exports);
20
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../lib/functions/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,mFAAiE;AACjE,oFAAkE;AAClE,8CAA4B"}
@@ -0,0 +1,9 @@
1
+ export * from './AccessTokenClient';
2
+ export * from './CredentialOfferClient';
3
+ export * from './CredentialRequestClient';
4
+ export * from './CredentialRequestClientBuilder';
5
+ export * from './functions';
6
+ export * from './MetadataClient';
7
+ export * from './OpenID4VCIClient';
8
+ export * from './ProofOfPossessionBuilder';
9
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../lib/index.ts"],"names":[],"mappings":"AAAA,cAAc,qBAAqB,CAAC;AACpC,cAAc,yBAAyB,CAAC;AACxC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,kCAAkC,CAAC;AACjD,cAAc,aAAa,CAAC;AAC5B,cAAc,kBAAkB,CAAC;AACjC,cAAc,oBAAoB,CAAC;AACnC,cAAc,4BAA4B,CAAC"}
@@ -1,24 +1,25 @@
1
- "use strict";
2
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
- if (k2 === undefined) k2 = k;
4
- var desc = Object.getOwnPropertyDescriptor(m, k);
5
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
- desc = { enumerable: true, get: function() { return m[k]; } };
7
- }
8
- Object.defineProperty(o, k2, desc);
9
- }) : (function(o, m, k, k2) {
10
- if (k2 === undefined) k2 = k;
11
- o[k2] = m[k];
12
- }));
13
- var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
- for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
- };
16
- Object.defineProperty(exports, "__esModule", { value: true });
17
- __exportStar(require("./functions"), exports);
18
- __exportStar(require("./types"), exports);
19
- __exportStar(require("./MetadataClient"), exports);
20
- __exportStar(require("./IssuanceInitiation"), exports);
21
- __exportStar(require("./AccessTokenClient"), exports);
22
- __exportStar(require("./CredentialRequestClient"), exports);
23
- __exportStar(require("./CredentialRequestClientBuilder"), exports);
24
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9saWIvaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7Ozs7Ozs7OztBQUFBLDhDQUE0QjtBQUM1QiwwQ0FBd0I7QUFDeEIsbURBQWlDO0FBQ2pDLHVEQUFxQztBQUNyQyxzREFBb0M7QUFDcEMsNERBQTBDO0FBQzFDLG1FQUFpRCJ9
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ __exportStar(require("./AccessTokenClient"), exports);
18
+ __exportStar(require("./CredentialOfferClient"), exports);
19
+ __exportStar(require("./CredentialRequestClient"), exports);
20
+ __exportStar(require("./CredentialRequestClientBuilder"), exports);
21
+ __exportStar(require("./functions"), exports);
22
+ __exportStar(require("./MetadataClient"), exports);
23
+ __exportStar(require("./OpenID4VCIClient"), exports);
24
+ __exportStar(require("./ProofOfPossessionBuilder"), exports);
25
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../lib/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,sDAAoC;AACpC,0DAAwC;AACxC,4DAA0C;AAC1C,mEAAiD;AACjD,8CAA4B;AAC5B,mDAAiC;AACjC,qDAAmC;AACnC,6DAA2C"}
@@ -0,0 +1,249 @@
1
+ import {
2
+ AccessTokenRequest,
3
+ AccessTokenRequestOpts,
4
+ AccessTokenResponse,
5
+ assertedUniformCredentialOffer,
6
+ AuthorizationServerOpts,
7
+ EndpointMetadata,
8
+ getIssuerFromCredentialOfferPayload,
9
+ GrantTypes,
10
+ isPreAuthCode,
11
+ IssuerOpts,
12
+ OpenIDResponse,
13
+ PRE_AUTH_CODE_LITERAL,
14
+ TokenErrorResponse,
15
+ toUniformCredentialOfferRequest,
16
+ UniformCredentialOfferPayload,
17
+ } from '@sphereon/oid4vci-common';
18
+ import { ObjectUtils } from '@sphereon/ssi-types';
19
+ import Debug from 'debug';
20
+
21
+ import { MetadataClient } from './MetadataClient';
22
+ import { convertJsonToURI, formPost } from './functions';
23
+
24
+ const debug = Debug('sphereon:oid4vci:token');
25
+
26
+ export class AccessTokenClient {
27
+ public async acquireAccessToken(opts: AccessTokenRequestOpts): Promise<OpenIDResponse<AccessTokenResponse>> {
28
+ const { asOpts, pin, codeVerifier, code, redirectUri, metadata } = opts;
29
+
30
+ const credentialOffer = await assertedUniformCredentialOffer(opts.credentialOffer);
31
+ const isPinRequired = this.isPinRequiredValue(credentialOffer.credential_offer);
32
+ const issuer = getIssuerFromCredentialOfferPayload(credentialOffer.credential_offer) ?? (metadata?.issuer as string);
33
+ if (!issuer) {
34
+ throw Error('Issuer required at this point');
35
+ }
36
+ const issuerOpts = {
37
+ issuer,
38
+ };
39
+
40
+ return await this.acquireAccessTokenUsingRequest({
41
+ accessTokenRequest: await this.createAccessTokenRequest({
42
+ credentialOffer,
43
+ asOpts,
44
+ codeVerifier,
45
+ code,
46
+ redirectUri,
47
+ pin,
48
+ }),
49
+ isPinRequired,
50
+ metadata,
51
+ asOpts,
52
+ issuerOpts,
53
+ });
54
+ }
55
+
56
+ public async acquireAccessTokenUsingRequest({
57
+ accessTokenRequest,
58
+ isPinRequired,
59
+ metadata,
60
+ asOpts,
61
+ issuerOpts,
62
+ }: {
63
+ accessTokenRequest: AccessTokenRequest;
64
+ isPinRequired?: boolean;
65
+ metadata?: EndpointMetadata;
66
+ asOpts?: AuthorizationServerOpts;
67
+ issuerOpts?: IssuerOpts;
68
+ }): Promise<OpenIDResponse<AccessTokenResponse>> {
69
+ this.validate(accessTokenRequest, isPinRequired);
70
+ const requestTokenURL = AccessTokenClient.determineTokenURL({
71
+ asOpts,
72
+ issuerOpts,
73
+ metadata: metadata
74
+ ? metadata
75
+ : issuerOpts?.fetchMetadata
76
+ ? await MetadataClient.retrieveAllMetadata(issuerOpts.issuer, { errorOnNotFound: false })
77
+ : undefined,
78
+ });
79
+ return this.sendAuthCode(requestTokenURL, accessTokenRequest);
80
+ }
81
+
82
+ public async createAccessTokenRequest(opts: AccessTokenRequestOpts): Promise<AccessTokenRequest> {
83
+ const { asOpts, pin, codeVerifier, code, redirectUri } = opts;
84
+ const credentialOfferRequest = await toUniformCredentialOfferRequest(opts.credentialOffer);
85
+ const request: Partial<AccessTokenRequest> = {};
86
+ if (asOpts?.clientId) {
87
+ request.client_id = asOpts.clientId;
88
+ }
89
+
90
+ this.assertNumericPin(this.isPinRequiredValue(credentialOfferRequest.credential_offer), pin);
91
+ request.user_pin = pin;
92
+
93
+ const isPreAuth = isPreAuthCode(credentialOfferRequest);
94
+ if (isPreAuth) {
95
+ if (codeVerifier) {
96
+ throw new Error('Cannot pass a code_verifier when flow type is pre-authorized');
97
+ }
98
+ request.grant_type = GrantTypes.PRE_AUTHORIZED_CODE;
99
+ // we actually know it is there because of the isPreAuthCode call
100
+ request[PRE_AUTH_CODE_LITERAL] =
101
+ credentialOfferRequest?.credential_offer.grants?.['urn:ietf:params:oauth:grant-type:pre-authorized_code']?.[PRE_AUTH_CODE_LITERAL];
102
+ }
103
+ if (!isPreAuth && credentialOfferRequest.credential_offer.grants?.authorization_code?.issuer_state) {
104
+ this.throwNotSupportedFlow(); // not supported yet
105
+ request.grant_type = GrantTypes.AUTHORIZATION_CODE;
106
+ }
107
+ if (codeVerifier) {
108
+ request.code_verifier = codeVerifier;
109
+ request.code = code;
110
+ request.redirect_uri = redirectUri;
111
+ request.grant_type = GrantTypes.AUTHORIZATION_CODE;
112
+ }
113
+ if (request.grant_type === GrantTypes.AUTHORIZATION_CODE && isPreAuth) {
114
+ throw Error('A pre_authorized_code flow cannot have an issuer state in the credential offer');
115
+ }
116
+
117
+ return request as AccessTokenRequest;
118
+ }
119
+
120
+ private assertPreAuthorizedGrantType(grantType: GrantTypes): void {
121
+ if (GrantTypes.PRE_AUTHORIZED_CODE !== grantType) {
122
+ throw new Error("grant type must be 'urn:ietf:params:oauth:grant-type:pre-authorized_code'");
123
+ }
124
+ }
125
+
126
+ private assertAuthorizationGrantType(grantType: GrantTypes): void {
127
+ if (GrantTypes.AUTHORIZATION_CODE !== grantType) {
128
+ throw new Error("grant type must be 'authorization_code'");
129
+ }
130
+ }
131
+
132
+ private isPinRequiredValue(requestPayload: UniformCredentialOfferPayload): boolean {
133
+ let isPinRequired = false;
134
+ if (!requestPayload) {
135
+ throw new Error(TokenErrorResponse.invalid_request);
136
+ }
137
+ const issuer = getIssuerFromCredentialOfferPayload(requestPayload);
138
+ if (requestPayload.grants?.['urn:ietf:params:oauth:grant-type:pre-authorized_code']) {
139
+ isPinRequired = requestPayload.grants['urn:ietf:params:oauth:grant-type:pre-authorized_code']?.user_pin_required ?? false;
140
+ }
141
+ debug(`Pin required for issuer ${issuer}: ${isPinRequired}`);
142
+ return isPinRequired;
143
+ }
144
+
145
+ private assertNumericPin(isPinRequired?: boolean, pin?: string): void {
146
+ if (isPinRequired) {
147
+ if (!pin || !/^\d{1,8}$/.test(pin)) {
148
+ debug(`Pin is not 1 to 8 digits long`);
149
+ throw new Error('A valid pin consisting of maximal 8 numeric characters must be present.');
150
+ }
151
+ } else if (pin) {
152
+ debug(`Pin set, whilst not required`);
153
+ throw new Error('Cannot set a pin, when the pin is not required.');
154
+ }
155
+ }
156
+
157
+ private assertNonEmptyPreAuthorizedCode(accessTokenRequest: AccessTokenRequest): void {
158
+ if (!accessTokenRequest[PRE_AUTH_CODE_LITERAL]) {
159
+ debug(`No pre-authorized code present, whilst it is required`);
160
+ throw new Error('Pre-authorization must be proven by presenting the pre-authorized code. Code must be present.');
161
+ }
162
+ }
163
+
164
+ private assertNonEmptyCodeVerifier(accessTokenRequest: AccessTokenRequest): void {
165
+ if (!accessTokenRequest.code_verifier) {
166
+ debug('No code_verifier present, whilst it is required');
167
+ throw new Error('Authorization flow requires the code_verifier to be present');
168
+ }
169
+ }
170
+
171
+ private assertNonEmptyCode(accessTokenRequest: AccessTokenRequest): void {
172
+ if (!accessTokenRequest.code) {
173
+ debug('No code present, whilst it is required');
174
+ throw new Error('Authorization flow requires the code to be present');
175
+ }
176
+ }
177
+
178
+ private assertNonEmptyRedirectUri(accessTokenRequest: AccessTokenRequest): void {
179
+ if (!accessTokenRequest.redirect_uri) {
180
+ debug('No redirect_uri present, whilst it is required');
181
+ throw new Error('Authorization flow requires the redirect_uri to be present');
182
+ }
183
+ }
184
+
185
+ private validate(accessTokenRequest: AccessTokenRequest, isPinRequired?: boolean): void {
186
+ if (accessTokenRequest.grant_type === GrantTypes.PRE_AUTHORIZED_CODE) {
187
+ this.assertPreAuthorizedGrantType(accessTokenRequest.grant_type);
188
+ this.assertNonEmptyPreAuthorizedCode(accessTokenRequest);
189
+ this.assertNumericPin(isPinRequired, accessTokenRequest.user_pin);
190
+ } else if (accessTokenRequest.grant_type === GrantTypes.AUTHORIZATION_CODE) {
191
+ this.assertAuthorizationGrantType(accessTokenRequest.grant_type);
192
+ this.assertNonEmptyCodeVerifier(accessTokenRequest);
193
+ this.assertNonEmptyCode(accessTokenRequest);
194
+ this.assertNonEmptyRedirectUri(accessTokenRequest);
195
+ } else {
196
+ this.throwNotSupportedFlow;
197
+ }
198
+ }
199
+
200
+ private async sendAuthCode(requestTokenURL: string, accessTokenRequest: AccessTokenRequest): Promise<OpenIDResponse<AccessTokenResponse>> {
201
+ return await formPost(requestTokenURL, convertJsonToURI(accessTokenRequest));
202
+ }
203
+
204
+ public static determineTokenURL({
205
+ asOpts,
206
+ issuerOpts,
207
+ metadata,
208
+ }: {
209
+ asOpts?: AuthorizationServerOpts;
210
+ issuerOpts?: IssuerOpts;
211
+ metadata?: EndpointMetadata;
212
+ }): string {
213
+ if (!asOpts && !metadata?.token_endpoint && !issuerOpts) {
214
+ throw new Error('Cannot determine token URL if no issuer, metadata and no Authorization Server values are present');
215
+ }
216
+ let url;
217
+ if (asOpts && asOpts.as) {
218
+ url = this.creatTokenURLFromURL(asOpts.as, asOpts?.allowInsecureEndpoints, asOpts.tokenEndpoint);
219
+ } else if (metadata?.token_endpoint) {
220
+ url = metadata.token_endpoint;
221
+ } else {
222
+ if (!issuerOpts?.issuer) {
223
+ throw Error('Either authorization server options, a token endpoint or issuer options are required at this point');
224
+ }
225
+ url = this.creatTokenURLFromURL(issuerOpts.issuer, asOpts?.allowInsecureEndpoints, issuerOpts.tokenEndpoint);
226
+ }
227
+
228
+ if (!url || !ObjectUtils.isString(url)) {
229
+ throw new Error('No authorization server token URL present. Cannot acquire access token');
230
+ }
231
+ debug(`Token endpoint determined to be ${url}`);
232
+ return url;
233
+ }
234
+
235
+ private static creatTokenURLFromURL(url: string, allowInsecureEndpoints?: boolean, tokenEndpoint?: string): string {
236
+ if (allowInsecureEndpoints !== true && url.startsWith('http:')) {
237
+ throw Error(`Unprotected token endpoints are not allowed ${url}. Adjust settings if you really need this (dev/test settings only!!)`);
238
+ }
239
+ const hostname = url.replace(/https?:\/\//, '').replace(/\/$/, '');
240
+ const endpoint = tokenEndpoint ? (tokenEndpoint.startsWith('/') ? tokenEndpoint : tokenEndpoint.substring(1)) : '/token';
241
+ const scheme = url.split('://')[0];
242
+ return `${scheme ? scheme + '://' : 'https://'}${hostname}${endpoint}`;
243
+ }
244
+
245
+ private throwNotSupportedFlow(): void {
246
+ debug(`Only pre-authorized flow supported.`);
247
+ throw new Error('Only pre-authorized-code flow is supported');
248
+ }
249
+ }
@@ -0,0 +1,46 @@
1
+ import { AuthorizationDetailsJwtVcJson, OID4VCICredentialFormat } from '@sphereon/oid4vci-common';
2
+
3
+ //todo: refactor this builder to be able to create ldp details as well
4
+ export class AuthorizationDetailsBuilder {
5
+ private readonly authorizationDetails: Partial<AuthorizationDetailsJwtVcJson>;
6
+
7
+ constructor() {
8
+ this.authorizationDetails = {};
9
+ }
10
+
11
+ withType(type: string): AuthorizationDetailsBuilder {
12
+ this.authorizationDetails.type = type;
13
+ return this;
14
+ }
15
+
16
+ withFormats(format: OID4VCICredentialFormat): AuthorizationDetailsBuilder {
17
+ this.authorizationDetails.format = format;
18
+ return this;
19
+ }
20
+
21
+ withLocations(locations: string[]): AuthorizationDetailsBuilder {
22
+ if (this.authorizationDetails.locations) {
23
+ this.authorizationDetails.locations.push(...locations);
24
+ } else {
25
+ this.authorizationDetails.locations = locations;
26
+ }
27
+ return this;
28
+ }
29
+
30
+ addLocation(location: string): AuthorizationDetailsBuilder {
31
+ if (this.authorizationDetails.locations) {
32
+ this.authorizationDetails.locations.push(location);
33
+ } else {
34
+ this.authorizationDetails.locations = [location];
35
+ }
36
+ return this;
37
+ }
38
+
39
+ //todo: we have to consider one thing, if this is a general purpose builder, we want to support ldp types here as well. and for that we need a few checks.
40
+ buildJwtVcJson(): AuthorizationDetailsJwtVcJson {
41
+ if (this.authorizationDetails.format && this.authorizationDetails.type) {
42
+ return this.authorizationDetails as AuthorizationDetailsJwtVcJson;
43
+ }
44
+ throw new Error('Type and format are required properties');
45
+ }
46
+ }
@@ -0,0 +1,108 @@
1
+ import {
2
+ CredentialOffer,
3
+ CredentialOfferPayload,
4
+ CredentialOfferPayloadV1_0_09,
5
+ CredentialOfferRequestWithBaseUrl,
6
+ CredentialOfferV1_0_11,
7
+ determineSpecVersionFromURI,
8
+ OpenId4VCIVersion,
9
+ toUniformCredentialOfferRequest,
10
+ } from '@sphereon/oid4vci-common';
11
+ import Debug from 'debug';
12
+
13
+ import { convertJsonToURI, convertURIToJsonObject } from './functions';
14
+
15
+ const debug = Debug('sphereon:oid4vci:offer');
16
+
17
+ export class CredentialOfferClient {
18
+ public static async fromURI(uri: string, opts?: { resolve?: boolean }): Promise<CredentialOfferRequestWithBaseUrl> {
19
+ debug(`Credential Offer URI: ${uri}`);
20
+ if (!uri.includes('?') || !uri.includes('://')) {
21
+ debug(`Invalid Credential Offer URI: ${uri}`);
22
+ throw Error(`Invalid Credential Offer Request`);
23
+ }
24
+ const scheme = uri.split('://')[0];
25
+ const baseUrl = uri.split('?')[0];
26
+ const version = determineSpecVersionFromURI(uri);
27
+ let credentialOffer: CredentialOffer;
28
+ let credentialOfferPayload: CredentialOfferPayload;
29
+ if (version < OpenId4VCIVersion.VER_1_0_11) {
30
+ credentialOfferPayload = convertURIToJsonObject(uri, {
31
+ arrayTypeProperties: ['credential_type'],
32
+ requiredProperties: uri.includes('credential_offer_uri=') ? ['credential_offer_uri'] : ['issuer', 'credential_type'],
33
+ }) as CredentialOfferPayloadV1_0_09;
34
+ credentialOffer = {
35
+ credential_offer: credentialOfferPayload,
36
+ };
37
+ } else {
38
+ credentialOffer = convertURIToJsonObject(uri, {
39
+ arrayTypeProperties: ['credentials'],
40
+ requiredProperties: uri.includes('credential_offer_uri=') ? ['credential_offer_uri'] : ['credential_offer'],
41
+ }) as CredentialOfferV1_0_11;
42
+ if (credentialOffer?.credential_offer_uri === undefined && !credentialOffer?.credential_offer) {
43
+ throw Error('Either a credential_offer or credential_offer_uri should be present in ' + uri);
44
+ }
45
+ }
46
+ const request = await toUniformCredentialOfferRequest(credentialOffer, {
47
+ ...opts,
48
+ version,
49
+ });
50
+
51
+ const grants = request.credential_offer?.grants;
52
+
53
+ return {
54
+ scheme,
55
+ baseUrl,
56
+ ...request,
57
+ ...(grants?.authorization_code?.issuer_state && { issuerState: grants.authorization_code.issuer_state }),
58
+ ...(grants?.['urn:ietf:params:oauth:grant-type:pre-authorized_code']?.['pre-authorized_code'] && {
59
+ preAuthorizedCode: grants['urn:ietf:params:oauth:grant-type:pre-authorized_code']['pre-authorized_code'],
60
+ }),
61
+ userPinRequired: request.credential_offer?.grants?.['urn:ietf:params:oauth:grant-type:pre-authorized_code']?.user_pin_required ?? false,
62
+ };
63
+ }
64
+
65
+ public static toURI(
66
+ requestWithBaseUrl: CredentialOfferRequestWithBaseUrl,
67
+ opts?: {
68
+ version?: OpenId4VCIVersion;
69
+ }
70
+ ): string {
71
+ debug(`Credential Offer Request with base URL: ${JSON.stringify(requestWithBaseUrl)}`);
72
+ const version = opts?.version ?? requestWithBaseUrl.version;
73
+ let baseUrl = requestWithBaseUrl.baseUrl.includes(requestWithBaseUrl.scheme)
74
+ ? requestWithBaseUrl.baseUrl
75
+ : `${requestWithBaseUrl.scheme.replace('://', '')}://${requestWithBaseUrl.baseUrl}`;
76
+ let param: string | undefined;
77
+
78
+ const isUri = requestWithBaseUrl.credential_offer_uri !== undefined;
79
+
80
+ if (version.valueOf() >= OpenId4VCIVersion.VER_1_0_11.valueOf()) {
81
+ // v11 changed from encoding every param to a encoded json object with a credential_offer param key
82
+ if (!baseUrl.includes('?')) {
83
+ param = isUri ? 'credential_offer_uri' : 'credential_offer';
84
+ } else {
85
+ const split = baseUrl.split('?');
86
+ if (split.length > 1 && split[1] !== '') {
87
+ if (baseUrl.endsWith('&')) {
88
+ param = isUri ? 'credential_offer_uri' : 'credential_offer';
89
+ } else if (!baseUrl.endsWith('=')) {
90
+ baseUrl += `&`;
91
+ param = isUri ? 'credential_offer_uri' : 'credential_offer';
92
+ }
93
+ }
94
+ }
95
+ }
96
+ return convertJsonToURI(requestWithBaseUrl.credential_offer_uri ?? requestWithBaseUrl.original_credential_offer, {
97
+ baseUrl,
98
+ arrayTypeProperties: isUri ? [] : ['credential_type'],
99
+ uriTypeProperties: isUri
100
+ ? ['credential_offer_uri']
101
+ : version >= OpenId4VCIVersion.VER_1_0_11
102
+ ? ['credential_issuer', 'credential_type']
103
+ : ['issuer', 'credential_type'],
104
+ param,
105
+ version,
106
+ });
107
+ }
108
+ }