@payware/mcp-server 1.1.1 → 1.2.0

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/.env.example +0 -0
  2. package/MCP-SETUP.md +0 -0
  3. package/README.md +17 -16
  4. package/check-keys.js +0 -0
  5. package/keys/README.md +0 -0
  6. package/mcp-config.json +0 -0
  7. package/package.json +1 -1
  8. package/payware-mcp-config.json +0 -0
  9. package/src/auth/rsa-keys.js +0 -0
  10. package/src/auth/sandbox-setup.js +2 -2
  11. package/src/config/env.js +0 -0
  12. package/src/config/partner-types.js +0 -0
  13. package/src/core/auth/jwt-factory.js +4 -4
  14. package/src/core/auth/jwt-token.js +107 -66
  15. package/src/core/utils/json-serializer.js +5 -5
  16. package/src/core/utils/key-utils.js +0 -0
  17. package/src/index.js +0 -0
  18. package/src/isv/data/index.js +0 -0
  19. package/src/isv/deep-links/delete-product-link.js +0 -0
  20. package/src/isv/deep-links/delete-transaction-link.js +0 -0
  21. package/src/isv/deep-links/get-product-link.js +0 -0
  22. package/src/isv/deep-links/get-transaction-link.js +0 -0
  23. package/src/isv/deep-links/index.js +0 -0
  24. package/src/isv/index.js +0 -0
  25. package/src/isv/oauth2/create-token-simple.js +0 -0
  26. package/src/isv/oauth2/get-token-info.js +0 -0
  27. package/src/isv/oauth2/obtain-token.js +0 -0
  28. package/src/isv/oauth2/token-helper.js +0 -0
  29. package/src/isv/poi/cancel-price.js +0 -0
  30. package/src/isv/poi/get-poi.js +0 -0
  31. package/src/isv/poi/get-qrcode.js +0 -0
  32. package/src/isv/poi/get-status.js +0 -0
  33. package/src/isv/poi/index.js +0 -0
  34. package/src/isv/poi/list-pois.js +0 -0
  35. package/src/isv/poi/set-price.js +0 -0
  36. package/src/isv/products/audios.js +0 -0
  37. package/src/isv/products/create-product.js +0 -0
  38. package/src/isv/products/delete-product.js +0 -0
  39. package/src/isv/products/get-product-image.js +0 -0
  40. package/src/isv/products/get-product.js +0 -0
  41. package/src/isv/products/index.js +0 -0
  42. package/src/isv/products/list-products.js +0 -0
  43. package/src/isv/products/schedules.js +0 -0
  44. package/src/isv/products/update-product.js +0 -0
  45. package/src/isv/transactions/cancel-transaction.js +2 -2
  46. package/src/isv/transactions/create-transaction.js +2 -2
  47. package/src/isv/transactions/get-status.js +0 -0
  48. package/src/isv/transactions/process-transaction.js +2 -2
  49. package/src/isv/transactions/simulate-callback.js +2 -2
  50. package/src/isv/transactions/transaction-history.js +0 -0
  51. package/src/isv/utils/auth.js +2 -2
  52. package/src/mcp-proxy.js +0 -0
  53. package/src/merchant/data/export-report.js +0 -0
  54. package/src/merchant/data/generate-report.js +0 -0
  55. package/src/merchant/data/get-export-list.js +0 -0
  56. package/src/merchant/data/get-report-requests.js +0 -0
  57. package/src/merchant/data/get-report-status.js +0 -0
  58. package/src/merchant/data/index.js +0 -0
  59. package/src/merchant/data/list-reports.js +0 -0
  60. package/src/merchant/deep-links/delete-product-link.js +0 -0
  61. package/src/merchant/deep-links/delete-transaction-link.js +0 -0
  62. package/src/merchant/deep-links/get-product-link.js +0 -0
  63. package/src/merchant/deep-links/get-transaction-link.js +0 -0
  64. package/src/merchant/deep-links/index.js +0 -0
  65. package/src/merchant/index.js +0 -0
  66. package/src/merchant/products/audios.js +0 -0
  67. package/src/merchant/products/create-product.js +0 -0
  68. package/src/merchant/products/delete-product.js +0 -0
  69. package/src/merchant/products/get-product-image.js +0 -0
  70. package/src/merchant/products/get-product.js +0 -0
  71. package/src/merchant/products/index.js +0 -0
  72. package/src/merchant/products/list-products.js +0 -0
  73. package/src/merchant/products/schedules.js +0 -0
  74. package/src/merchant/products/update-product.js +0 -0
  75. package/src/merchant/transactions/cancel-transaction.js +6 -6
  76. package/src/merchant/transactions/create-transaction.js +13 -13
  77. package/src/merchant/transactions/get-status.js +1 -1
  78. package/src/merchant/transactions/process-transaction.js +6 -6
  79. package/src/merchant/transactions/simulate-callback.js +0 -0
  80. package/src/merchant/transactions/transaction-history.js +1 -1
  81. package/src/payment-institution/data/index.js +0 -0
  82. package/src/payment-institution/deep-links/delete-transaction-link.js +0 -0
  83. package/src/payment-institution/deep-links/get-transaction-link.js +0 -0
  84. package/src/payment-institution/deep-links/index.js +0 -0
  85. package/src/payment-institution/index.js +0 -0
  86. package/src/payment-institution/transactions/create-pi-transaction.js +4 -4
  87. package/src/payment-institution/transactions/finalize-transaction.js +3 -3
  88. package/src/payment-institution/transactions/get-transaction-history.js +1 -1
  89. package/src/payment-institution/transactions/get-transaction-status.js +1 -1
  90. package/src/payment-institution/transactions/process-pi-transaction.js +3 -3
  91. package/src/payment-institution/transactions/simulate-pi-callback.js +0 -0
  92. package/src/payment-institution/transactions/soundbite-transaction.js +3 -3
  93. package/src/proxy-server.js +0 -0
  94. package/src/shared/data/data-api.js +0 -0
  95. package/src/shared/deep-links/api.js +0 -0
  96. package/src/shared/index.js +0 -0
  97. package/src/shared/products/products-api.js +0 -0
  98. package/src/tools/advanced-code-generator.js +53 -53
  99. package/src/utils/code-examples/common/auth-examples.js +38 -38
  100. package/src/utils/code-examples/common/helpers.js +0 -0
  101. package/src/utils/code-examples/common/utils-examples.js +0 -0
  102. package/src/utils/code-examples/frameworks/examples.js +4 -4
  103. package/src/utils/code-examples/index.js +0 -0
  104. package/src/utils/code-examples/isv/oauth2.js +0 -0
  105. package/src/utils/code-examples/isv/products.js +8 -8
  106. package/src/utils/code-examples/isv/transactions.js +9 -9
  107. package/src/utils/code-examples/merchant/products.js +0 -0
  108. package/src/utils/code-examples/merchant/transactions.js +9 -9
  109. package/src/utils/code-examples/payment-institution/transactions.js +0 -0
  110. package/src/utils/code-examples/shared/data.js +0 -0
  111. package/src/utils/code-examples/shared/deep-links.js +0 -0
  112. package/src/utils/code-examples/shared/soundbites.js +0 -0
  113. package/src/utils/code-examples.js +24 -24
  114. package/src/utils/format-request.js +3 -3
  115. package/src/utils/json-formatter.js +20 -20
  116. package/src/utils/server-info.js +0 -0
package/.env.example CHANGED
File without changes
package/MCP-SETUP.md CHANGED
File without changes
package/README.md CHANGED
@@ -10,10 +10,11 @@ Official MCP (Model Context Protocol) server for payware payment API integration
10
10
  - **ISVs (Independent Software Vendors)** - Build multi-merchant platforms with OAuth2 token management
11
11
  - **Payment Institutions** - Process A2A transfers, handle Payment Choice Architecture with multiple payment methods
12
12
 
13
- ## What's New in v1.1.0
13
+ ## What's New in v1.2.0
14
14
 
15
- - **Point of Interaction (POI)** - Full POI management: set prices, get status, generate QR codes, list and manage POIs
16
- - **Payment Choice Architecture** - Support for `paymentMethod` field (A2A, CARD_FUNDED, BNPL, INSTANT_CREDIT) in transaction processing
15
+ - **SHA-256 Authentication** - Upgraded from MD5 to SHA-256 for JWT content hashing (`contentSha256` header)
16
+ - **Updated Error Codes** - New error codes: `ERR_INVALID_CONTENT_HASH`, `ERR_MISSING_CONTENT_HASH`
17
+ - **Backward Compatibility** - Deprecated MD5 functions retained for legacy support
17
18
 
18
19
  ## Features
19
20
 
@@ -375,7 +376,7 @@ Generate comprehensive API documentation with code examples.
375
376
  - `outputFormat` (optional): markdown, html, json (default: markdown)
376
377
 
377
378
  #### `payware_utils_format_request`
378
- Format and validate API requests with deterministic JSON serialization for MD5 consistency.
379
+ Format and validate API requests with deterministic JSON serialization for SHA-256 consistency.
379
380
 
380
381
  **Parameters:**
381
382
  - `type` (required): transaction, headers, or curl
@@ -386,7 +387,7 @@ Format and validate API requests with deterministic JSON serialization for MD5 c
386
387
  - `method` (optional): HTTP method (default: POST)
387
388
 
388
389
  #### `payware_utils_format_json_deterministic`
389
- Format JSON with deterministic property ordering for consistent MD5 calculation.
390
+ Format JSON with deterministic property ordering for consistent SHA-256 calculation.
390
391
 
391
392
  **Parameters:**
392
393
  - `data` (required): Object to serialize
@@ -395,7 +396,7 @@ Format JSON with deterministic property ordering for consistent MD5 calculation.
395
396
  #### `payware_utils_server_info`
396
397
  Get MCP server information and configuration.
397
398
 
398
- **Note:** All transaction data is serialized using consistent property ordering to prevent MD5 mismatch errors.
399
+ **Note:** All transaction data is serialized using consistent property ordering to prevent content hash mismatch errors.
399
400
 
400
401
  ## Dependencies
401
402
 
@@ -435,12 +436,12 @@ Get MCP server information and configuration.
435
436
  - Validate all input parameters
436
437
  - Implement rate limiting and monitoring
437
438
 
438
- ### JSON Serialization & MD5 Consistency
439
- ⚠️ **CRITICAL**: payware API requires deterministic JSON serialization for MD5 calculation
439
+ ### JSON Serialization & SHA-256 Consistency
440
+ ⚠️ **CRITICAL**: payware API requires deterministic JSON serialization for SHA-256 calculation
440
441
 
441
442
  - **Property Order**: JSON objects must have consistent property ordering
442
443
  - **Minimized Format**: No whitespace or formatting in request bodies
443
- - **MD5 Calculation**: Must be calculated from the exact same JSON string sent to API
444
+ - **SHA-256 Calculation**: Must be calculated from the exact same JSON string sent to API
444
445
  - **Implementation**: This server uses deterministic JSON serialization to ensure consistency
445
446
 
446
447
  **Example of correct JSON format:**
@@ -449,9 +450,9 @@ Get MCP server information and configuration.
449
450
  ```
450
451
 
451
452
  **Why this matters:**
452
- - Different property orders produce different MD5 hashes
453
- - MD5 mismatch results in `ContentMd5 mismatch` errors
454
- - Server validates that JWT contentMd5 matches request body MD5
453
+ - Different property orders produce different SHA-256 hashes
454
+ - Hash mismatch results in `ERR_INVALID_CONTENT_HASH` errors
455
+ - Server validates that JWT `contentSha256` matches request body SHA-256
455
456
 
456
457
  ## Troubleshooting
457
458
 
@@ -463,11 +464,11 @@ Get MCP server information and configuration.
463
464
  - **Verification**: Use `openssl rsa -in privateKey.pem -pubout` to extract public key from private key
464
465
  - **Status**: ✅ Resolved - Keys must be properly registered on payware partner portal
465
466
 
466
- 2. **ContentMd5 Mismatch Error**
467
+ 2. **Content Hash Mismatch Error (ERR_INVALID_CONTENT_HASH)**
467
468
  - **Root Cause**: Inconsistent JSON property ordering
468
469
  - **Solution**: Use deterministic JSON serialization (implemented in this server)
469
- - **Symptoms**: Server logs show different expected vs actual MD5 hashes
470
- - **Prevention**: Always use `createMinimizedJSON()` from `/src/utils/json-serializer.js`
470
+ - **Symptoms**: Server logs show different expected vs actual SHA-256 hashes
471
+ - **Prevention**: Always use `createMinimizedJSON()` from `/src/core/utils/json-serializer.js`
471
472
  - **Status**: ✅ Fixed - Deterministic JSON serialization implemented
472
473
 
473
474
  3. **Transaction Creation Failed**
@@ -500,7 +501,7 @@ Get MCP server information and configuration.
500
501
  - JWT token creation with RS256 algorithm
501
502
  - Transaction creation (POST /api/transactions)
502
503
  - Transaction cancellation (PATCH /api/transactions/{id})
503
- - Deterministic JSON serialization for MD5 consistency
504
+ - Deterministic JSON serialization for SHA-256 consistency
504
505
  - Public/private key pair validation
505
506
 
506
507
  **🧪 Test Results:**
package/check-keys.js CHANGED
File without changes
package/keys/README.md CHANGED
File without changes
package/mcp-config.json CHANGED
File without changes
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@payware/mcp-server",
3
- "version": "1.1.1",
3
+ "version": "1.2.0",
4
4
  "description": "Official MCP server for payware payment API integration",
5
5
  "main": "src/index.js",
6
6
  "type": "module",
File without changes
File without changes
@@ -155,13 +155,13 @@ ${JSON.stringify(config, null, 2)}
155
155
 
156
156
  **Required Headers (All Requests):**
157
157
  ${Object.entries(config.headers).map(([key, value]) => `- ${key}: ${value}`).join('\n')}
158
- - Authorization: Bearer {JWT_TOKEN} (with contentMd5 for POST/PATCH)
158
+ - Authorization: Bearer {JWT_TOKEN} (with contentSha256 for POST/PATCH)
159
159
 
160
160
  **JWT Requirements:**
161
161
  - Algorithm: RS256
162
162
  - Issuer (iss): Your Partner ID
163
163
  - Audience (aud): https://payware.eu
164
- - Content-MD5: Required in JWT header for POST/PATCH requests
164
+ - Content-SHA256: Required in JWT header for POST/PATCH requests
165
165
  - Private Key: RSA 2048-bit minimum
166
166
 
167
167
  **Required Fields for Transaction Creation:**
package/src/config/env.js CHANGED
File without changes
File without changes
@@ -99,7 +99,7 @@ async function createISVJWT({ isvPartnerId, merchantPartnerId, oauth2Token, priv
99
99
  * Create JWT token with custom payload (for ISV use case)
100
100
  * @param {Object} payload - Custom JWT payload
101
101
  * @param {string} privateKey - Private key for signing
102
- * @param {Object} requestBody - Request body for content MD5
102
+ * @param {Object} requestBody - Request body for content SHA-256
103
103
  * @returns {Object} JWT token data
104
104
  */
105
105
  async function createJWTTokenWithCustomPayload(payload, privateKey, requestBody) {
@@ -116,11 +116,11 @@ async function createJWTTokenWithCustomPayload(payload, privateKey, requestBody)
116
116
  typ: 'JWT'
117
117
  };
118
118
 
119
- // Add contentMd5 to header if request body exists
119
+ // Add contentSha256 to header if request body exists (SHA-256 is preferred over MD5)
120
120
  if (requestBody) {
121
121
  const { createMinimizedJSON } = await import('../utils/json-serializer.js');
122
122
  const bodyString = createMinimizedJSON(requestBody);
123
- header.contentMd5 = crypto.default.createHash('md5').update(bodyString, 'utf8').digest('base64');
123
+ header.contentSha256 = crypto.default.createHash('sha256').update(bodyString, 'utf8').digest('base64');
124
124
  }
125
125
 
126
126
  const token = jwt.default.sign(payload, normalizedKey, {
@@ -134,7 +134,7 @@ async function createJWTTokenWithCustomPayload(payload, privateKey, requestBody)
134
134
  audience: payload.aud,
135
135
  subject: payload.sub,
136
136
  issuedAt: new Date(payload.iat * 1000).toISOString(),
137
- contentMd5: header.contentMd5 || null,
137
+ contentSha256: header.contentSha256 || null,
138
138
  hasBody: !!requestBody,
139
139
  isISV: true
140
140
  };
@@ -5,14 +5,36 @@ import { getPartnerIdSafe, getPrivateKeySafe } from '../../config/env.js';
5
5
  import { createDeterministicJSON } from '../utils/json-serializer.js';
6
6
 
7
7
  /**
8
- * Generate MD5 hash for JWT contentMd5 header
8
+ * Generate SHA-256 hash for JWT contentSha256 header (PREFERRED)
9
9
  *
10
- * PAYWARE REQUIREMENT: The MD5 hash must be calculated from the EXACT same
10
+ * PAYWARE REQUIREMENT: The SHA-256 hash must be calculated from the EXACT same
11
11
  * compact JSON string that will be sent as the HTTP request body.
12
12
  *
13
13
  * CRITICAL: Any difference in whitespace, property order, or formatting
14
- * between the string used for MD5 and the HTTP body will cause authentication
15
- * failures with ERR_INVALID_MD5 errors.
14
+ * between the string used for hash and the HTTP body will cause authentication
15
+ * failures with ERR_INVALID_CONTENT_HASH errors.
16
+ *
17
+ * @param {Object|string} body - Request body (object will be consistently serialized)
18
+ * @returns {string} Base64 encoded SHA-256 hash for JWT contentSha256 header
19
+ */
20
+ export function generateContentSha256(body) {
21
+ if (!body) return null;
22
+
23
+ // CRITICAL: Use deterministic JSON serialization with sorted keys
24
+ // This ensures consistent hashes regardless of property order
25
+ const bodyString = typeof body === 'string' ? body : createDeterministicJSON(body);
26
+
27
+ // Generate SHA-256 hash as raw binary and encode in base64
28
+ const hash = crypto.createHash('sha256');
29
+ hash.update(bodyString, 'utf8');
30
+ return hash.digest('base64');
31
+ }
32
+
33
+ /**
34
+ * Generate MD5 hash for JWT contentMd5 header (DEPRECATED - use generateContentSha256)
35
+ *
36
+ * @deprecated Use generateContentSha256 instead. MD5 is still supported by the server
37
+ * for backwards compatibility but is deprecated.
16
38
  *
17
39
  * @param {Object|string} body - Request body (object will be consistently serialized)
18
40
  * @returns {string} Base64 encoded MD5 hash for JWT contentMd5 header
@@ -20,8 +42,6 @@ import { createDeterministicJSON } from '../utils/json-serializer.js';
20
42
  export function generateContentMd5(body) {
21
43
  if (!body) return null;
22
44
 
23
- // CRITICAL: Use deterministic JSON serialization with sorted keys
24
- // This ensures consistent MD5 hashes regardless of property order
25
45
  const bodyString = typeof body === 'string' ? body : createDeterministicJSON(body);
26
46
 
27
47
  // Generate MD5 hash as raw binary and encode in base64
@@ -31,17 +51,17 @@ export function generateContentMd5(body) {
31
51
  }
32
52
 
33
53
  /**
34
- * Generate the exact JSON string for both JWT MD5 and HTTP request body
54
+ * Generate the exact JSON string for both JWT content hash and HTTP request body
35
55
  *
36
56
  * PAYWARE REQUIREMENT: The same compact JSON string must be used for:
37
- * 1. JWT contentMd5 calculation (passed to generateContentMd5)
57
+ * 1. JWT contentSha256 calculation (passed to generateContentSha256)
38
58
  * 2. HTTP request body (sent to payware API)
39
59
  *
40
60
  * This function guarantees consistency by using deterministic serialization.
41
61
  * Any mismatch between these two uses will result in authentication failure.
42
62
  *
43
63
  * @param {Object} payload - Request payload object
44
- * @returns {string} Compact JSON string for both MD5 and HTTP body
64
+ * @returns {string} Compact JSON string for both hash calculation and HTTP body
45
65
  */
46
66
  export function serializePayload(payload) {
47
67
  if (!payload) return null;
@@ -71,11 +91,11 @@ export function createJWTToken(partnerId, privateKey, requestBody = null) {
71
91
  typ: 'JWT'
72
92
  };
73
93
 
74
- // Add contentMd5 to header if request body exists (for POST/PUT/PATCH)
94
+ // Add contentSha256 to header if request body exists (for POST/PUT/PATCH)
75
95
  // CRITICAL: The requestBody here must be the EXACT same string that will
76
- // be sent as the HTTP request body, otherwise MD5 will not match
96
+ // be sent as the HTTP request body, otherwise hash will not match
77
97
  if (requestBody) {
78
- header.contentMd5 = generateContentMd5(requestBody);
98
+ header.contentSha256 = generateContentSha256(requestBody);
79
99
  }
80
100
 
81
101
  // JWT Payload (as per documentation)
@@ -95,7 +115,7 @@ export function createJWTToken(partnerId, privateKey, requestBody = null) {
95
115
  partnerId,
96
116
  audience: 'https://payware.eu',
97
117
  issuedAt: new Date(now * 1000).toISOString(),
98
- contentMd5: header.contentMd5 || null,
118
+ contentSha256: header.contentSha256 || null,
99
119
  hasBody: !!requestBody
100
120
  };
101
121
  }
@@ -125,7 +145,7 @@ export function createRequestSignature(method, path, body, privateKey) {
125
145
  */
126
146
  export const validateJWTTokenTool = {
127
147
  name: "payware_authentication_validate_jwt",
128
- description: "Validate and debug JWT token structure, decode payload/headers, verify MD5 calculation, and check RS256 signature format for payware API compliance",
148
+ description: "Validate and debug JWT token structure, decode payload/headers, verify content hash (SHA-256/MD5) calculation, and check RS256 signature format for payware API compliance",
129
149
  inputSchema: {
130
150
  type: "object",
131
151
  properties: {
@@ -135,7 +155,7 @@ export const validateJWTTokenTool = {
135
155
  },
136
156
  expectedPayload: {
137
157
  type: "object",
138
- description: "Expected request body (optional - for MD5 validation)"
158
+ description: "Expected request body (optional - for content hash validation)"
139
159
  }
140
160
  },
141
161
  required: ["jwtToken"],
@@ -159,6 +179,11 @@ export const validateJWTTokenTool = {
159
179
 
160
180
  const { header, payload } = decoded;
161
181
 
182
+ // Determine which hash type is used
183
+ const hasContentSha256 = !!header.contentSha256;
184
+ const hasContentMd5 = !!header.contentMd5;
185
+ const hasContentHash = hasContentSha256 || hasContentMd5;
186
+
162
187
  // Validation results
163
188
  const validation = {
164
189
  structure: true,
@@ -167,19 +192,31 @@ export const validateJWTTokenTool = {
167
192
  audience: payload.aud === 'https://payware.eu',
168
193
  issuer: !!payload.iss,
169
194
  issuedAt: !!payload.iat,
170
- contentMd5: header.contentMd5 ? true : false
195
+ contentHash: hasContentHash
171
196
  };
172
197
 
173
- // MD5 validation if expected payload provided
174
- let md5Validation = null;
175
- if (expectedPayload && header.contentMd5) {
176
- const calculatedMd5 = generateContentMd5(expectedPayload);
177
- md5Validation = {
178
- provided: header.contentMd5,
179
- calculated: calculatedMd5,
180
- matches: header.contentMd5 === calculatedMd5,
181
- deterministicJson: createDeterministicJSON(expectedPayload)
182
- };
198
+ // Content hash validation if expected payload provided
199
+ let hashValidation = null;
200
+ if (expectedPayload && hasContentHash) {
201
+ if (hasContentSha256) {
202
+ const calculatedSha256 = generateContentSha256(expectedPayload);
203
+ hashValidation = {
204
+ type: 'SHA-256 (preferred)',
205
+ provided: header.contentSha256,
206
+ calculated: calculatedSha256,
207
+ matches: header.contentSha256 === calculatedSha256,
208
+ deterministicJson: createDeterministicJSON(expectedPayload)
209
+ };
210
+ } else if (hasContentMd5) {
211
+ const calculatedMd5 = generateContentMd5(expectedPayload);
212
+ hashValidation = {
213
+ type: 'MD5 (deprecated)',
214
+ provided: header.contentMd5,
215
+ calculated: calculatedMd5,
216
+ matches: header.contentMd5 === calculatedMd5,
217
+ deterministicJson: createDeterministicJSON(expectedPayload)
218
+ };
219
+ }
183
220
  }
184
221
 
185
222
  // Check for common issues
@@ -189,11 +226,14 @@ export const validateJWTTokenTool = {
189
226
  if (!validation.audience) issues.push("Audience should be 'https://payware.eu'");
190
227
  if (!validation.issuer) issues.push("Missing issuer (iss) claim");
191
228
  if (!validation.issuedAt) issues.push("Missing issued at (iat) claim");
192
- if (md5Validation && !md5Validation.matches) {
193
- issues.push("MD5 hash mismatch - ensure deterministic JSON serialization with sorted keys");
229
+ if (hasContentMd5 && !hasContentSha256) {
230
+ issues.push("Using deprecated MD5 hash - consider upgrading to SHA-256 (contentSha256)");
231
+ }
232
+ if (hashValidation && !hashValidation.matches) {
233
+ issues.push("Content hash mismatch - ensure deterministic JSON serialization with sorted keys");
194
234
  }
195
235
 
196
- const overallValid = Object.values(validation).every(v => v) && (!md5Validation || md5Validation.matches);
236
+ const overallValid = Object.values(validation).every(v => v) && (!hashValidation || hashValidation.matches);
197
237
 
198
238
  return {
199
239
  content: [{
@@ -222,26 +262,26 @@ ${validation.type ? '✅' : '❌'} **Type**: JWT ${validation.type ? '(correct)'
222
262
  ${validation.audience ? '✅' : '❌'} **Audience**: https://payware.eu ${validation.audience ? '(correct)' : `(found: ${payload.aud})`}
223
263
  ${validation.issuer ? '✅' : '❌'} **Issuer**: ${payload.iss || 'Missing'}
224
264
  ${validation.issuedAt ? '✅' : '❌'} **Issued At**: ${payload.iat ? new Date(payload.iat * 1000).toISOString() : 'Missing'}
225
- ${validation.contentMd5 ? '✅' : 'ℹ️'} **Content MD5**: ${header.contentMd5 || 'Not present (OK for GET requests)'}
265
+ ${validation.contentHash ? '✅' : 'ℹ️'} **Content Hash**: ${header.contentSha256 ? `SHA-256: ${header.contentSha256}` : header.contentMd5 ? `MD5 (deprecated): ${header.contentMd5}` : 'Not present (OK for GET requests)'}
226
266
 
227
- ${md5Validation ? `## MD5 Hash Validation
267
+ ${hashValidation ? `## Content Hash Validation
228
268
 
229
- ${md5Validation.matches ? '✅' : '❌'} **MD5 Match**: ${md5Validation.matches ? 'Correct' : 'Mismatch detected'}
230
- **Provided**: \`${md5Validation.provided}\`
231
- **Calculated**: \`${md5Validation.calculated}\`
269
+ ${hashValidation.matches ? '✅' : '❌'} **${hashValidation.type} Match**: ${hashValidation.matches ? 'Correct' : 'Mismatch detected'}
270
+ **Provided**: \`${hashValidation.provided}\`
271
+ **Calculated**: \`${hashValidation.calculated}\`
232
272
 
233
273
  **Deterministic JSON Used**:
234
274
  \`\`\`json
235
- ${md5Validation.deterministicJson}
275
+ ${hashValidation.deterministicJson}
236
276
  \`\`\`
237
277
 
238
- ${!md5Validation.matches ? `
239
- ⚠️ **MD5 Mismatch Debugging**:
278
+ ${!hashValidation.matches ? `
279
+ ⚠️ **Hash Mismatch Debugging**:
240
280
 
241
- PAYWARE REQUIREMENT: The EXACT same compact JSON string must be used for both JWT contentMd5 and HTTP body.
281
+ PAYWARE REQUIREMENT: The EXACT same compact JSON string must be used for both JWT content hash and HTTP body.
242
282
 
243
283
  **Common Causes**:
244
- 1. Different JSON strings used for JWT MD5 vs HTTP body
284
+ 1. Different JSON strings used for JWT hash vs HTTP body
245
285
  2. Extra whitespace or formatting differences
246
286
  3. Property order variations between serializations
247
287
 
@@ -268,7 +308,7 @@ ${issues.includes("Type should be 'JWT'") ? '- Set JWT type to "JWT"\n' : ''}
268
308
  ${issues.includes("Audience should be 'https://payware.eu'") ? '- Set audience to "https://payware.eu" (not just "payware")\n' : ''}
269
309
  ${issues.includes("Missing issuer (iss) claim") ? '- Add your partner ID as the issuer claim\n' : ''}
270
310
  ${issues.includes("Missing issued at (iat) claim") ? '- Add current Unix timestamp as issued at claim\n' : ''}
271
- ${issues.some(i => i.includes('MD5 hash mismatch')) ? '- Use deterministic JSON serialization with sorted keys\n- Ensure same JSON string for MD5 and HTTP body\n' : ''}
311
+ ${issues.some(i => i.includes('hash mismatch')) ? '- Use deterministic JSON serialization with sorted keys\n- Ensure same JSON string for hash calculation and HTTP body\n' : ''}
272
312
  ` : '## ✅ No Issues Found\n\nYour JWT token is properly formatted for payware API usage.'}
273
313
 
274
314
  ## Technical Details
@@ -324,7 +364,7 @@ ${issues.some(i => i.includes('MD5 hash mismatch')) ? '- Use deterministic JSON
324
364
  */
325
365
  export const testJWTTokenTool = {
326
366
  name: "payware_authentication_test_jwt",
327
- description: "Test JWT token creation process with detailed step-by-step breakdown, showing deterministic JSON serialization, MD5 calculation, and final JWT structure",
367
+ description: "Test JWT token creation process with detailed step-by-step breakdown, showing deterministic JSON serialization, SHA-256 hash calculation, and final JWT structure",
328
368
  inputSchema: {
329
369
  type: "object",
330
370
  properties: {
@@ -334,7 +374,7 @@ export const testJWTTokenTool = {
334
374
  },
335
375
  requestPayload: {
336
376
  type: "object",
337
- description: "Sample request payload to demonstrate MD5 calculation"
377
+ description: "Sample request payload to demonstrate SHA-256 hash calculation"
338
378
  },
339
379
  showPrivateKey: {
340
380
  type: "boolean",
@@ -387,27 +427,27 @@ ${deterministicJson}
387
427
 
388
428
  **Key Sorting**: [${sortedKeys.join(', ')}]`);
389
429
 
390
- // Step 2: MD5 Calculation
391
- const md5Hash = generateContentMd5(requestPayload);
430
+ // Step 2: SHA-256 Calculation
431
+ const sha256Hash = generateContentSha256(requestPayload);
392
432
 
393
- steps.push(`**Step 2: MD5 Hash Calculation**
433
+ steps.push(`**Step 2: SHA-256 Hash Calculation**
394
434
  Using deterministic JSON string:
395
435
  \`\`\`
396
436
  ${deterministicJson}
397
437
  \`\`\`
398
438
 
399
- MD5 hash (Base64): \`${md5Hash}\`
439
+ SHA-256 hash (Base64): \`${sha256Hash}\`
400
440
 
401
441
  **Process**:
402
- 1. Create MD5 hash from UTF-8 bytes of deterministic JSON
442
+ 1. Create SHA-256 hash from UTF-8 bytes of deterministic JSON
403
443
  2. Encode hash as Base64
404
- 3. Include in JWT header as \`contentMd5\``);
444
+ 3. Include in JWT header as \`contentSha256\``);
405
445
 
406
446
  // Step 3: JWT Header Construction
407
447
  const jwtHeader = {
408
448
  alg: 'RS256',
409
449
  typ: 'JWT',
410
- contentMd5: md5Hash
450
+ contentSha256: sha256Hash
411
451
  };
412
452
 
413
453
  steps.push(`**Step 3: JWT Header Construction**
@@ -418,7 +458,7 @@ ${JSON.stringify(jwtHeader, null, 2)}
418
458
  **Requirements**:
419
459
  - Algorithm: RS256 (RSA with SHA-256)
420
460
  - Type: JWT
421
- - Content MD5: ${md5Hash}`);
461
+ - Content SHA-256: ${sha256Hash}`);
422
462
 
423
463
  // Step 4: JWT Payload Construction
424
464
  const now = Math.floor(Date.now() / 1000);
@@ -498,18 +538,19 @@ ${deterministicJson}
498
538
  ## 🔑 **Key Insights**
499
539
 
500
540
  1. **Deterministic JSON is Critical**: Property order MUST be sorted
501
- 2. **MD5 Consistency**: Same JSON string for both MD5 and HTTP body
541
+ 2. **Hash Consistency**: Same JSON string for both SHA-256 hash and HTTP body
502
542
  3. **Audience Requirement**: Must be "https://payware.eu" (include https://)
503
543
  4. **RS256 Algorithm**: RSA with SHA-256 signature
504
- 5. **Content MD5 in Header**: Not in payload, but in JWT header
544
+ 5. **Content Hash in Header**: Not in payload, but in JWT header (use contentSha256)
505
545
 
506
546
  ## 🐛 **Common Mistakes to Avoid**
507
547
 
508
548
  ❌ Using \`JSON.stringify()\` without sorted keys
509
- ❌ Different JSON for MD5 vs HTTP request
549
+ ❌ Different JSON for hash calculation vs HTTP request
510
550
  ❌ Setting audience to "payware" instead of "https://payware.eu"
511
- ❌ Putting contentMd5 in payload instead of header
551
+ ❌ Putting contentSha256 in payload instead of header
512
552
  ❌ Using wrong algorithm (HS256 instead of RS256)
553
+ ❌ Using deprecated contentMd5 instead of contentSha256
513
554
 
514
555
  ---
515
556
  **Execution Info:**
@@ -567,7 +608,7 @@ export const createJWTTokenTool = {
567
608
  },
568
609
  requestBody: {
569
610
  type: "object",
570
- description: "Request body (for POST/PUT/PATCH requests that need contentMd5)"
611
+ description: "Request body (for POST/PUT/PATCH requests that need contentSha256)"
571
612
  }
572
613
  },
573
614
  additionalProperties: false
@@ -619,14 +660,14 @@ ${tokenData.token}
619
660
  - Issued At (iat): ${tokenData.issuedAt}
620
661
  - Algorithm: RS256
621
662
  - Type: JWT
622
- ${tokenData.contentMd5 ? `- Content MD5: ${tokenData.contentMd5}` : '- Content MD5: Not included (no request body)'}
663
+ ${tokenData.contentSha256 ? `- Content SHA-256: ${tokenData.contentSha256}` : '- Content SHA-256: Not included (no request body)'}
623
664
 
624
665
  **JWT Structure (Decoded):**
625
666
  **Header:**
626
667
  \`\`\`json
627
668
  {
628
669
  "alg": "RS256",
629
- "typ": "JWT"${tokenData.contentMd5 ? `,\n "contentMd5": "${tokenData.contentMd5}"` : ''}
670
+ "typ": "JWT"${tokenData.contentSha256 ? `,\n "contentSha256": "${tokenData.contentSha256}"` : ''}
630
671
  }
631
672
  \`\`\`
632
673
 
@@ -653,7 +694,7 @@ Content-Type: application/json
653
694
  - ✅ Issuer: Your Partner ID
654
695
  - ✅ Audience: https://payware.eu
655
696
  - ✅ Issued At: Unix timestamp
656
- ${tokenData.contentMd5 ? '- ✅ Content MD5: Included for request body' : '- ℹ️ Content MD5: Not needed for GET requests'}
697
+ ${tokenData.contentSha256 ? '- ✅ Content SHA-256: Included for request body' : '- ℹ️ Content SHA-256: Not needed for GET requests'}
657
698
 
658
699
  **📝 Private Key Formats Supported:**
659
700
  - ✅ Full PEM format with headers/footers
@@ -663,9 +704,9 @@ ${tokenData.contentMd5 ? '- ✅ Content MD5: Included for request body' : '- ℹ
663
704
  ## ⚠️ **CRITICAL AUTHENTICATION REQUIREMENTS**
664
705
 
665
706
  ### JSON Body Consistency Rule
666
- ${tokenData.contentMd5 ? `**Your contentMd5 (${tokenData.contentMd5}) MUST match the exact bytes sent in HTTP request.**
707
+ ${tokenData.contentSha256 ? `**Your contentSha256 (${tokenData.contentSha256}) MUST match the exact bytes sent in HTTP request.**
667
708
 
668
- ❌ **Common Error Causing ERR_INVALID_MD5:**
709
+ ❌ **Common Error Causing ERR_INVALID_CONTENT_HASH:**
669
710
  \`\`\`python
670
711
  # Wrong - different serialization formats!
671
712
  jwt_token = create_jwt(json.dumps(payload)) # One format
@@ -674,18 +715,18 @@ requests.post(url, json=payload) # Different format!
674
715
 
675
716
  ✅ **Correct Implementation:**
676
717
  \`\`\`python
677
- # Same serialization for both MD5 and HTTP body
718
+ # Same serialization for both hash and HTTP body
678
719
  json_body = json.dumps(payload, separators=(',', ':')) # Compact format
679
720
  jwt_token = create_jwt(json_body)
680
721
  requests.post(url, data=json_body, headers=headers)
681
722
  \`\`\`
682
- ` : '**No request body - No MD5 consistency concerns for GET requests.**'}
723
+ ` : '**No request body - No hash consistency concerns for GET requests.**'}
683
724
 
684
725
  ### Troubleshooting Authentication Errors
685
726
 
686
- **ERR_INVALID_MD5** - MD5 hash mismatch:
687
- - Cause: JWT contentMd5 doesn't match HTTP request body bytes
688
- - Fix: Use identical JSON serialization for both MD5 calculation and HTTP request
727
+ **ERR_INVALID_CONTENT_HASH** - Content hash mismatch:
728
+ - Cause: JWT contentSha256 doesn't match HTTP request body bytes
729
+ - Fix: Use identical JSON serialization for both hash calculation and HTTP request
689
730
  - Common issue: \`requests.post(json=data)\` vs \`requests.post(data=json_string)\`
690
731
 
691
732
  **ERR_INVALID_SIGNATURE** - JWT signature validation failed:
@@ -718,7 +759,7 @@ const response = await axios.post(url, jsonBody, {headers: {'Authorization': \`B
718
759
  - Do not share or log this token
719
760
  - Generate new token for each request with different body
720
761
  - Ensure your public key is registered with payware
721
- - **Critical:** Always use matching JSON serialization for MD5 and HTTP body`
762
+ - **Critical:** Always use matching JSON serialization for SHA-256 hash and HTTP body`
722
763
  }]
723
764
  };
724
765
  } catch (error) {
@@ -2,7 +2,7 @@
2
2
  * JSON Consistency Utilities for payware API
3
3
  *
4
4
  * CORE REQUIREMENT: The exact same compact JSON string must be used for
5
- * both JWT contentMd5 calculation and HTTP request body to prevent MD5 mismatches.
5
+ * both JWT contentSha256 calculation and HTTP request body to prevent hash mismatches.
6
6
  *
7
7
  * SOLUTION: We use deterministic serialization (sorted keys) to guarantee
8
8
  * consistent JSON output regardless of object property insertion order.
@@ -15,10 +15,10 @@
15
15
  * Create consistent compact JSON string for payware API requests
16
16
  *
17
17
  * CORE REQUIREMENT: payware API requires that the exact same compact JSON string
18
- * is used for both JWT contentMd5 calculation and the HTTP request body.
18
+ * is used for both JWT contentSha256 calculation and the HTTP request body.
19
19
  *
20
20
  * SOLUTION: This function uses deterministic serialization with sorted keys
21
- * to guarantee the same output every time, preventing MD5 mismatch errors.
21
+ * to guarantee the same output every time, preventing hash mismatch errors.
22
22
  *
23
23
  * @param {Object} obj - Object to serialize
24
24
  * @returns {string} Compact JSON string with sorted keys (no whitespace)
@@ -72,7 +72,7 @@ function sortObjectKeys(obj) {
72
72
  *
73
73
  * payware REQUIRES:
74
74
  * 1. JSON must be compact (no extra whitespace)
75
- * 2. The EXACT same string must be used for JWT contentMd5 and HTTP body
75
+ * 2. The EXACT same string must be used for JWT contentSha256 and HTTP body
76
76
  *
77
77
  * This function ensures both requirements by using deterministic serialization.
78
78
  *
@@ -86,7 +86,7 @@ export function createMinimizedJSON(requestBody) {
86
86
  /**
87
87
  * Validate that two objects produce the same JSON string
88
88
  *
89
- * This is crucial for payware API because the JWT contentMd5 and HTTP body
89
+ * This is crucial for payware API because the JWT contentSha256 and HTTP body
90
90
  * must use the exact same string. This function helps test that requirement.
91
91
  *
92
92
  * @param {Object} obj1 - First object
File without changes
package/src/index.js CHANGED
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
package/src/isv/index.js CHANGED
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes