@payware/mcp-server 1.0.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.
- package/.env.example +92 -0
- package/MCP-SETUP.md +190 -0
- package/README.md +483 -0
- package/check-keys.js +52 -0
- package/keys/README.md +112 -0
- package/mcp-config.json +9 -0
- package/package.json +66 -0
- package/payware-mcp-config.json +12 -0
- package/src/auth/rsa-keys.js +82 -0
- package/src/auth/sandbox-setup.js +187 -0
- package/src/config/env.js +229 -0
- package/src/config/partner-types.js +143 -0
- package/src/core/auth/jwt-factory.js +182 -0
- package/src/core/auth/jwt-token.js +735 -0
- package/src/core/utils/json-serializer.js +100 -0
- package/src/core/utils/key-utils.js +133 -0
- package/src/index.js +237 -0
- package/src/isv/data/index.js +291 -0
- package/src/isv/deep-links/delete-product-link.js +154 -0
- package/src/isv/deep-links/delete-transaction-link.js +154 -0
- package/src/isv/deep-links/get-product-link.js +167 -0
- package/src/isv/deep-links/get-transaction-link.js +167 -0
- package/src/isv/deep-links/index.js +23 -0
- package/src/isv/index.js +103 -0
- package/src/isv/oauth2/create-token-simple.js +46 -0
- package/src/isv/oauth2/get-token-info.js +157 -0
- package/src/isv/oauth2/obtain-token.js +189 -0
- package/src/isv/oauth2/token-helper.js +151 -0
- package/src/isv/products/audios.js +470 -0
- package/src/isv/products/create-product.js +314 -0
- package/src/isv/products/delete-product.js +119 -0
- package/src/isv/products/get-product-image.js +247 -0
- package/src/isv/products/get-product.js +168 -0
- package/src/isv/products/index.js +65 -0
- package/src/isv/products/list-products.js +136 -0
- package/src/isv/products/schedules.js +522 -0
- package/src/isv/products/update-product.js +265 -0
- package/src/isv/transactions/cancel-transaction.js +129 -0
- package/src/isv/transactions/create-transaction.js +361 -0
- package/src/isv/transactions/get-status.js +217 -0
- package/src/isv/transactions/process-transaction.js +145 -0
- package/src/isv/transactions/simulate-callback.js +146 -0
- package/src/isv/transactions/transaction-history.js +186 -0
- package/src/isv/utils/auth.js +159 -0
- package/src/mcp-proxy.js +150 -0
- package/src/merchant/data/export-report.js +108 -0
- package/src/merchant/data/generate-report.js +151 -0
- package/src/merchant/data/get-report-status.js +120 -0
- package/src/merchant/data/index.js +351 -0
- package/src/merchant/deep-links/delete-product-link.js +121 -0
- package/src/merchant/deep-links/delete-transaction-link.js +121 -0
- package/src/merchant/deep-links/get-product-link.js +134 -0
- package/src/merchant/deep-links/get-transaction-link.js +134 -0
- package/src/merchant/deep-links/index.js +23 -0
- package/src/merchant/index.js +92 -0
- package/src/merchant/products/audios.js +606 -0
- package/src/merchant/products/create-product.js +288 -0
- package/src/merchant/products/delete-product.js +111 -0
- package/src/merchant/products/get-product-image.js +252 -0
- package/src/merchant/products/get-product.js +144 -0
- package/src/merchant/products/index.js +65 -0
- package/src/merchant/products/list-products.js +112 -0
- package/src/merchant/products/schedules.js +646 -0
- package/src/merchant/products/update-product.js +282 -0
- package/src/merchant/transactions/cancel-transaction.js +241 -0
- package/src/merchant/transactions/create-transaction.js +482 -0
- package/src/merchant/transactions/get-status.js +196 -0
- package/src/merchant/transactions/process-transaction.js +349 -0
- package/src/merchant/transactions/simulate-callback.js +246 -0
- package/src/merchant/transactions/transaction-history.js +258 -0
- package/src/payment-institution/data/index.js +280 -0
- package/src/payment-institution/deep-links/delete-transaction-link.js +128 -0
- package/src/payment-institution/deep-links/get-transaction-link.js +141 -0
- package/src/payment-institution/deep-links/index.js +17 -0
- package/src/payment-institution/index.js +92 -0
- package/src/payment-institution/transactions/create-pi-transaction.js +484 -0
- package/src/payment-institution/transactions/finalize-transaction.js +340 -0
- package/src/payment-institution/transactions/get-transaction-history.js +269 -0
- package/src/payment-institution/transactions/get-transaction-status.js +234 -0
- package/src/payment-institution/transactions/process-pi-transaction.js +421 -0
- package/src/payment-institution/transactions/simulate-pi-callback.js +326 -0
- package/src/payment-institution/transactions/soundbite-transaction.js +269 -0
- package/src/proxy-server.js +205 -0
- package/src/shared/data/data-api.js +372 -0
- package/src/shared/deep-links/api.js +214 -0
- package/src/shared/index.js +44 -0
- package/src/shared/products/products-api.js +872 -0
- package/src/tools/advanced-code-generator.js +2247 -0
- package/src/utils/code-examples/common/auth-examples.js +1482 -0
- package/src/utils/code-examples/common/helpers.js +416 -0
- package/src/utils/code-examples/common/utils-examples.js +591 -0
- package/src/utils/code-examples/frameworks/examples.js +859 -0
- package/src/utils/code-examples/index.js +441 -0
- package/src/utils/code-examples/isv/oauth2.js +600 -0
- package/src/utils/code-examples/isv/products.js +666 -0
- package/src/utils/code-examples/isv/transactions.js +813 -0
- package/src/utils/code-examples/merchant/products.js +497 -0
- package/src/utils/code-examples/merchant/transactions.js +623 -0
- package/src/utils/code-examples/payment-institution/transactions.js +388 -0
- package/src/utils/code-examples/shared/data.js +607 -0
- package/src/utils/code-examples/shared/deep-links.js +662 -0
- package/src/utils/code-examples/shared/soundbites.js +808 -0
- package/src/utils/code-examples.js +646 -0
- package/src/utils/format-request.js +363 -0
- package/src/utils/json-formatter.js +249 -0
- package/src/utils/server-info.js +132 -0
|
@@ -0,0 +1,600 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ISV OAuth2 authentication flow examples
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { ExampleGenerator, CommonTemplates } from '../common/helpers.js';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* OAuth2 operations for ISV
|
|
9
|
+
*/
|
|
10
|
+
export const OAuth2Operations = {
|
|
11
|
+
obtain_token: {
|
|
12
|
+
description: 'Obtain OAuth2 access token for merchant access',
|
|
13
|
+
endpoint: '/oauth2/token',
|
|
14
|
+
method: 'POST',
|
|
15
|
+
sampleBody: {
|
|
16
|
+
grant_type: 'client_credentials',
|
|
17
|
+
client_id: 'YOUR_CLIENT_ID',
|
|
18
|
+
client_secret: 'YOUR_CLIENT_SECRET',
|
|
19
|
+
scope: 'merchant:transactions merchant:products merchant:data'
|
|
20
|
+
}
|
|
21
|
+
},
|
|
22
|
+
|
|
23
|
+
get_token_info: {
|
|
24
|
+
description: 'Get information about current OAuth2 token',
|
|
25
|
+
endpoint: '/oauth2/token/info',
|
|
26
|
+
method: 'GET',
|
|
27
|
+
sampleBody: null
|
|
28
|
+
},
|
|
29
|
+
|
|
30
|
+
create_token_simple: {
|
|
31
|
+
description: 'Create simple OAuth2 token with basic scope',
|
|
32
|
+
endpoint: '/oauth2/token/simple',
|
|
33
|
+
method: 'POST',
|
|
34
|
+
sampleBody: {
|
|
35
|
+
grant_type: 'client_credentials',
|
|
36
|
+
scope: 'merchant:read'
|
|
37
|
+
}
|
|
38
|
+
},
|
|
39
|
+
|
|
40
|
+
refresh_token: {
|
|
41
|
+
description: 'Refresh an existing OAuth2 token',
|
|
42
|
+
endpoint: '/oauth2/token/refresh',
|
|
43
|
+
method: 'POST',
|
|
44
|
+
sampleBody: {
|
|
45
|
+
grant_type: 'refresh_token',
|
|
46
|
+
refresh_token: 'REFRESH_TOKEN_HERE'
|
|
47
|
+
}
|
|
48
|
+
},
|
|
49
|
+
|
|
50
|
+
revoke_token: {
|
|
51
|
+
description: 'Revoke OAuth2 access token',
|
|
52
|
+
endpoint: '/oauth2/token/revoke',
|
|
53
|
+
method: 'POST',
|
|
54
|
+
sampleBody: {
|
|
55
|
+
token: 'TOKEN_TO_REVOKE',
|
|
56
|
+
token_type_hint: 'access_token'
|
|
57
|
+
}
|
|
58
|
+
},
|
|
59
|
+
|
|
60
|
+
list_active_tokens: {
|
|
61
|
+
description: 'List all active OAuth2 tokens for ISV',
|
|
62
|
+
endpoint: '/oauth2/tokens',
|
|
63
|
+
method: 'GET',
|
|
64
|
+
sampleBody: null
|
|
65
|
+
}
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Python OAuth2 Generator
|
|
70
|
+
*/
|
|
71
|
+
export class PythonOAuth2Generator extends ExampleGenerator {
|
|
72
|
+
constructor() {
|
|
73
|
+
super('python');
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
getOperationTemplate(operation, partnerType, params = {}) {
|
|
77
|
+
const opConfig = OAuth2Operations[operation];
|
|
78
|
+
if (!opConfig) {
|
|
79
|
+
throw new Error(`Unknown operation: ${operation}`);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
const { merchantPartnerId = 'merchant_456', scope = 'merchant:full', ...otherParams } = params;
|
|
83
|
+
const functionName = `${operation}_example`;
|
|
84
|
+
|
|
85
|
+
return `def ${functionName}(merchant_partner_id='${merchantPartnerId}', scope='${scope}', use_sandbox=True):
|
|
86
|
+
"""${opConfig.description}"""
|
|
87
|
+
|
|
88
|
+
try:
|
|
89
|
+
# Get OAuth2 configuration
|
|
90
|
+
client_id = os.getenv('PAYWARE_OAUTH_CLIENT_ID')
|
|
91
|
+
client_secret = os.getenv('PAYWARE_OAUTH_CLIENT_SECRET')
|
|
92
|
+
|
|
93
|
+
if not client_id or not client_secret:
|
|
94
|
+
print("Missing OAuth2 credentials in environment")
|
|
95
|
+
return None
|
|
96
|
+
|
|
97
|
+
# Get API configuration
|
|
98
|
+
base_url = get_api_base_url(use_sandbox)
|
|
99
|
+
endpoint = '${opConfig.endpoint}'
|
|
100
|
+
url = f"{base_url}{endpoint}"
|
|
101
|
+
|
|
102
|
+
${this.getRequestBodySection(operation, opConfig, merchantPartnerId)}
|
|
103
|
+
|
|
104
|
+
# OAuth2 requests use application/x-www-form-urlencoded
|
|
105
|
+
headers = {
|
|
106
|
+
'Content-Type': 'application/x-www-form-urlencoded',
|
|
107
|
+
'Api-Version': '1'
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
${this.getRequestSection(opConfig.method)}
|
|
111
|
+
|
|
112
|
+
if response.status_code == 200:
|
|
113
|
+
result = response.json()
|
|
114
|
+
print(f"${opConfig.description} successful:")
|
|
115
|
+
print(json.dumps(result, indent=2))
|
|
116
|
+
|
|
117
|
+
${this.getResultProcessingSection(operation)}
|
|
118
|
+
return result
|
|
119
|
+
else:
|
|
120
|
+
error_msg = f"OAuth2 request failed with status {response.status_code}: {response.text}"
|
|
121
|
+
print(error_msg)
|
|
122
|
+
return None
|
|
123
|
+
|
|
124
|
+
except requests.exceptions.RequestException as e:
|
|
125
|
+
print(f"OAuth2 request error: {str(e)}")
|
|
126
|
+
return None
|
|
127
|
+
except Exception as e:
|
|
128
|
+
print(f"Unexpected error: {str(e)}")
|
|
129
|
+
return None
|
|
130
|
+
|
|
131
|
+
def get_oauth2_token_for_merchant(merchant_partner_id, scope='merchant:full', use_sandbox=True):
|
|
132
|
+
"""Convenience function to get OAuth2 token for specific merchant"""
|
|
133
|
+
|
|
134
|
+
client_id = os.getenv('PAYWARE_OAUTH_CLIENT_ID')
|
|
135
|
+
client_secret = os.getenv('PAYWARE_OAUTH_CLIENT_SECRET')
|
|
136
|
+
|
|
137
|
+
if not client_id or not client_secret:
|
|
138
|
+
raise ValueError("Missing OAuth2 credentials")
|
|
139
|
+
|
|
140
|
+
base_url = get_api_base_url(use_sandbox)
|
|
141
|
+
url = f"{base_url}/oauth2/token"
|
|
142
|
+
|
|
143
|
+
data = {
|
|
144
|
+
'grant_type': 'client_credentials',
|
|
145
|
+
'client_id': client_id,
|
|
146
|
+
'client_secret': client_secret,
|
|
147
|
+
'scope': f"merchant:{merchant_partner_id} {scope}"
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
headers = {
|
|
151
|
+
'Content-Type': 'application/x-www-form-urlencoded',
|
|
152
|
+
'Api-Version': '1'
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
try:
|
|
156
|
+
response = requests.post(url, data=data, headers=headers)
|
|
157
|
+
|
|
158
|
+
if response.status_code == 200:
|
|
159
|
+
token_data = response.json()
|
|
160
|
+
return token_data['access_token']
|
|
161
|
+
else:
|
|
162
|
+
print(f"OAuth2 token request failed: {response.status_code} - {response.text}")
|
|
163
|
+
return None
|
|
164
|
+
|
|
165
|
+
except Exception as e:
|
|
166
|
+
print(f"OAuth2 token error: {str(e)}")
|
|
167
|
+
return None
|
|
168
|
+
|
|
169
|
+
def validate_oauth2_token(access_token, use_sandbox=True):
|
|
170
|
+
"""Validate OAuth2 token and get token information"""
|
|
171
|
+
|
|
172
|
+
base_url = get_api_base_url(use_sandbox)
|
|
173
|
+
url = f"{base_url}/oauth2/token/info"
|
|
174
|
+
|
|
175
|
+
headers = {
|
|
176
|
+
'Authorization': f'Bearer {access_token}',
|
|
177
|
+
'Api-Version': '1'
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
try:
|
|
181
|
+
response = requests.get(url, headers=headers)
|
|
182
|
+
|
|
183
|
+
if response.status_code == 200:
|
|
184
|
+
token_info = response.json()
|
|
185
|
+
print("Token validation successful:")
|
|
186
|
+
print(f"- Valid: {token_info.get('active', False)}")
|
|
187
|
+
print(f"- Scope: {token_info.get('scope', 'N/A')}")
|
|
188
|
+
print(f"- Expires in: {token_info.get('expires_in', 'N/A')} seconds")
|
|
189
|
+
return token_info
|
|
190
|
+
else:
|
|
191
|
+
print(f"Token validation failed: {response.status_code}")
|
|
192
|
+
return None
|
|
193
|
+
|
|
194
|
+
except Exception as e:
|
|
195
|
+
print(f"Token validation error: {str(e)}")
|
|
196
|
+
return None
|
|
197
|
+
|
|
198
|
+
# Example usage
|
|
199
|
+
if __name__ == "__main__":
|
|
200
|
+
# Get target merchant from environment or use default
|
|
201
|
+
target_merchant = os.getenv('PAYWARE_TARGET_MERCHANT_ID', 'merchant_example')
|
|
202
|
+
|
|
203
|
+
print("=== OAuth2 Flow Example ===")
|
|
204
|
+
|
|
205
|
+
# Step 1: Obtain OAuth2 token
|
|
206
|
+
print("\\n1. Obtaining OAuth2 token...")
|
|
207
|
+
token_result = obtain_token_example(target_merchant)
|
|
208
|
+
|
|
209
|
+
if token_result and 'access_token' in token_result:
|
|
210
|
+
access_token = token_result['access_token']
|
|
211
|
+
print(f"✓ OAuth2 token obtained: {access_token[:20]}...")
|
|
212
|
+
|
|
213
|
+
# Step 2: Validate the token
|
|
214
|
+
print("\\n2. Validating OAuth2 token...")
|
|
215
|
+
validation_result = validate_oauth2_token(access_token)
|
|
216
|
+
|
|
217
|
+
if validation_result and validation_result.get('active'):
|
|
218
|
+
print("✓ Token is valid and active")
|
|
219
|
+
|
|
220
|
+
# Step 3: Use token for API calls
|
|
221
|
+
print("\\n3. Token ready for API calls")
|
|
222
|
+
print("You can now use this token with ISV JWT authentication")
|
|
223
|
+
else:
|
|
224
|
+
print("✗ Token validation failed")
|
|
225
|
+
else:
|
|
226
|
+
print("✗ Failed to obtain OAuth2 token")`;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
getRequestBodySection(operation, opConfig, merchantPartnerId) {
|
|
230
|
+
if (!opConfig.sampleBody) {
|
|
231
|
+
return '# No request body needed for this operation\n request_data = {}';
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
let body = { ...opConfig.sampleBody };
|
|
235
|
+
|
|
236
|
+
// Customize body based on operation
|
|
237
|
+
if (operation === 'obtain_token') {
|
|
238
|
+
body.scope = `merchant:${merchantPartnerId} ${body.scope}`;
|
|
239
|
+
body.client_id = 'client_id'; // Will be replaced by actual value
|
|
240
|
+
body.client_secret = 'client_secret'; // Will be replaced by actual value
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
const bodyEntries = Object.entries(body)
|
|
244
|
+
.map(([key, value]) => {
|
|
245
|
+
if (key === 'client_id') {
|
|
246
|
+
return " 'client_id': client_id,";
|
|
247
|
+
} else if (key === 'client_secret') {
|
|
248
|
+
return " 'client_secret': client_secret,";
|
|
249
|
+
} else {
|
|
250
|
+
return ` '${key}': '${value}',`;
|
|
251
|
+
}
|
|
252
|
+
})
|
|
253
|
+
.join('\n');
|
|
254
|
+
|
|
255
|
+
return `# Prepare OAuth2 request data
|
|
256
|
+
request_data = {
|
|
257
|
+
${bodyEntries}
|
|
258
|
+
}`;
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
getRequestSection(method) {
|
|
262
|
+
if (method === 'GET') {
|
|
263
|
+
return 'response = requests.get(url, headers=headers)';
|
|
264
|
+
} else {
|
|
265
|
+
return 'response = requests.post(url, data=request_data, headers=headers)';
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
getResultProcessingSection(operation) {
|
|
270
|
+
const processing = {
|
|
271
|
+
obtain_token: `# Store token information
|
|
272
|
+
access_token = result.get('access_token')
|
|
273
|
+
token_type = result.get('token_type', 'Bearer')
|
|
274
|
+
expires_in = result.get('expires_in')
|
|
275
|
+
scope = result.get('scope')
|
|
276
|
+
|
|
277
|
+
print(f"Access Token: {access_token[:20]}...")
|
|
278
|
+
print(f"Token Type: {token_type}")
|
|
279
|
+
print(f"Expires In: {expires_in} seconds")
|
|
280
|
+
print(f"Scope: {scope}")
|
|
281
|
+
|
|
282
|
+
# Store token for later use
|
|
283
|
+
os.environ['OAUTH2_ACCESS_TOKEN'] = access_token`,
|
|
284
|
+
|
|
285
|
+
get_token_info: `# Display token information
|
|
286
|
+
active = result.get('active', False)
|
|
287
|
+
scope = result.get('scope', 'N/A')
|
|
288
|
+
client_id = result.get('client_id', 'N/A')
|
|
289
|
+
expires_in = result.get('exp', 'N/A')
|
|
290
|
+
|
|
291
|
+
print(f"Token Active: {active}")
|
|
292
|
+
print(f"Client ID: {client_id}")
|
|
293
|
+
print(f"Scope: {scope}")
|
|
294
|
+
print(f"Expires: {expires_in}")`,
|
|
295
|
+
|
|
296
|
+
list_active_tokens: `# Display active tokens
|
|
297
|
+
tokens = result.get('tokens', [])
|
|
298
|
+
print(f"Found {len(tokens)} active tokens:")
|
|
299
|
+
for token in tokens:
|
|
300
|
+
print(f"- Token ID: {token.get('id')}")
|
|
301
|
+
print(f" Scope: {token.get('scope')}")
|
|
302
|
+
print(f" Created: {token.get('created_at')}")
|
|
303
|
+
print(f" Expires: {token.get('expires_at')}")`
|
|
304
|
+
};
|
|
305
|
+
|
|
306
|
+
return processing[operation] || '# Process OAuth2 result as needed';
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
/**
|
|
311
|
+
* Node.js OAuth2 Generator
|
|
312
|
+
*/
|
|
313
|
+
export class NodeJSOAuth2Generator extends ExampleGenerator {
|
|
314
|
+
constructor() {
|
|
315
|
+
super('nodejs');
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
getOperationTemplate(operation, partnerType, params = {}) {
|
|
319
|
+
const opConfig = OAuth2Operations[operation];
|
|
320
|
+
if (!opConfig) {
|
|
321
|
+
throw new Error(`Unknown operation: ${operation}`);
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
const { merchantPartnerId = 'merchant_456', scope = 'merchant:full', ...otherParams } = params;
|
|
325
|
+
const functionName = `${operation}Example`;
|
|
326
|
+
|
|
327
|
+
return `async function ${functionName}(merchantPartnerId = '${merchantPartnerId}', scope = '${scope}', useSandbox = true) {
|
|
328
|
+
/**
|
|
329
|
+
* ${opConfig.description}
|
|
330
|
+
*/
|
|
331
|
+
|
|
332
|
+
try {
|
|
333
|
+
// Get OAuth2 configuration
|
|
334
|
+
const clientId = process.env.PAYWARE_OAUTH_CLIENT_ID;
|
|
335
|
+
const clientSecret = process.env.PAYWARE_OAUTH_CLIENT_SECRET;
|
|
336
|
+
|
|
337
|
+
if (!clientId || !clientSecret) {
|
|
338
|
+
console.error('Missing OAuth2 credentials in environment');
|
|
339
|
+
return null;
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
// Get API configuration
|
|
343
|
+
const baseUrl = getAPIBaseURL(useSandbox);
|
|
344
|
+
const endpoint = '${opConfig.endpoint}';
|
|
345
|
+
const url = \`\${baseUrl}\${endpoint}\`;
|
|
346
|
+
|
|
347
|
+
${this.getRequestBodySection(operation, opConfig, merchantPartnerId)}
|
|
348
|
+
|
|
349
|
+
// OAuth2 requests use application/x-www-form-urlencoded
|
|
350
|
+
const headers = {
|
|
351
|
+
'Content-Type': 'application/x-www-form-urlencoded',
|
|
352
|
+
'Api-Version': '1'
|
|
353
|
+
};
|
|
354
|
+
|
|
355
|
+
${this.getRequestSection(opConfig.method)}
|
|
356
|
+
|
|
357
|
+
if (response.status === 200) {
|
|
358
|
+
const result = response.data;
|
|
359
|
+
console.log('${opConfig.description} successful:');
|
|
360
|
+
console.log(JSON.stringify(result, null, 2));
|
|
361
|
+
|
|
362
|
+
${this.getResultProcessingSection(operation)}
|
|
363
|
+
|
|
364
|
+
return result;
|
|
365
|
+
} else {
|
|
366
|
+
console.error(\`OAuth2 request failed with status \${response.status}: \${response.statusText}\`);
|
|
367
|
+
return null;
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
} catch (error) {
|
|
371
|
+
if (error.response) {
|
|
372
|
+
console.error(\`OAuth2 API Error: \${error.response.status} - \${error.response.data}\`);
|
|
373
|
+
} else {
|
|
374
|
+
console.error('OAuth2 Error:', error.message);
|
|
375
|
+
}
|
|
376
|
+
return null;
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
async function getOAuth2TokenForMerchant(merchantPartnerId, scope = 'merchant:full', useSandbox = true) {
|
|
381
|
+
/**
|
|
382
|
+
* Convenience function to get OAuth2 token for specific merchant
|
|
383
|
+
*/
|
|
384
|
+
|
|
385
|
+
const clientId = process.env.PAYWARE_OAUTH_CLIENT_ID;
|
|
386
|
+
const clientSecret = process.env.PAYWARE_OAUTH_CLIENT_SECRET;
|
|
387
|
+
|
|
388
|
+
if (!clientId || !clientSecret) {
|
|
389
|
+
throw new Error('Missing OAuth2 credentials');
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
const baseUrl = getAPIBaseURL(useSandbox);
|
|
393
|
+
const url = \`\${baseUrl}/oauth2/token\`;
|
|
394
|
+
|
|
395
|
+
const data = new URLSearchParams({
|
|
396
|
+
grant_type: 'client_credentials',
|
|
397
|
+
client_id: clientId,
|
|
398
|
+
client_secret: clientSecret,
|
|
399
|
+
scope: \`merchant:\${merchantPartnerId} \${scope}\`
|
|
400
|
+
});
|
|
401
|
+
|
|
402
|
+
const headers = {
|
|
403
|
+
'Content-Type': 'application/x-www-form-urlencoded',
|
|
404
|
+
'Api-Version': '1'
|
|
405
|
+
};
|
|
406
|
+
|
|
407
|
+
try {
|
|
408
|
+
const response = await axios.post(url, data, { headers });
|
|
409
|
+
|
|
410
|
+
if (response.status === 200) {
|
|
411
|
+
return response.data.access_token;
|
|
412
|
+
} else {
|
|
413
|
+
console.error(\`OAuth2 token request failed: \${response.status} - \${response.statusText}\`);
|
|
414
|
+
return null;
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
} catch (error) {
|
|
418
|
+
console.error('OAuth2 token error:', error.message);
|
|
419
|
+
return null;
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
async function validateOAuth2Token(accessToken, useSandbox = true) {
|
|
424
|
+
/**
|
|
425
|
+
* Validate OAuth2 token and get token information
|
|
426
|
+
*/
|
|
427
|
+
|
|
428
|
+
const baseUrl = getAPIBaseURL(useSandbox);
|
|
429
|
+
const url = \`\${baseUrl}/oauth2/token/info\`;
|
|
430
|
+
|
|
431
|
+
const headers = {
|
|
432
|
+
'Authorization': \`Bearer \${accessToken}\`,
|
|
433
|
+
'Api-Version': '1'
|
|
434
|
+
};
|
|
435
|
+
|
|
436
|
+
try {
|
|
437
|
+
const response = await axios.get(url, { headers });
|
|
438
|
+
|
|
439
|
+
if (response.status === 200) {
|
|
440
|
+
const tokenInfo = response.data;
|
|
441
|
+
console.log('Token validation successful:');
|
|
442
|
+
console.log(\`- Valid: \${tokenInfo.active || false}\`);
|
|
443
|
+
console.log(\`- Scope: \${tokenInfo.scope || 'N/A'}\`);
|
|
444
|
+
console.log(\`- Expires in: \${tokenInfo.expires_in || 'N/A'} seconds\`);
|
|
445
|
+
return tokenInfo;
|
|
446
|
+
} else {
|
|
447
|
+
console.error(\`Token validation failed: \${response.status}\`);
|
|
448
|
+
return null;
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
} catch (error) {
|
|
452
|
+
console.error('Token validation error:', error.message);
|
|
453
|
+
return null;
|
|
454
|
+
}
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
// Example usage
|
|
458
|
+
async function main() {
|
|
459
|
+
// Get target merchant from environment or use default
|
|
460
|
+
const targetMerchant = process.env.PAYWARE_TARGET_MERCHANT_ID || 'merchant_example';
|
|
461
|
+
|
|
462
|
+
console.log('=== OAuth2 Flow Example ===');
|
|
463
|
+
|
|
464
|
+
try {
|
|
465
|
+
// Step 1: Obtain OAuth2 token
|
|
466
|
+
console.log('\\n1. Obtaining OAuth2 token...');
|
|
467
|
+
const tokenResult = await obtainTokenExample(targetMerchant);
|
|
468
|
+
|
|
469
|
+
if (tokenResult && tokenResult.access_token) {
|
|
470
|
+
const accessToken = tokenResult.access_token;
|
|
471
|
+
console.log(\`✓ OAuth2 token obtained: \${accessToken.substring(0, 20)}...\`);
|
|
472
|
+
|
|
473
|
+
// Step 2: Validate the token
|
|
474
|
+
console.log('\\n2. Validating OAuth2 token...');
|
|
475
|
+
const validationResult = await validateOAuth2Token(accessToken);
|
|
476
|
+
|
|
477
|
+
if (validationResult && validationResult.active) {
|
|
478
|
+
console.log('✓ Token is valid and active');
|
|
479
|
+
|
|
480
|
+
// Step 3: Use token for API calls
|
|
481
|
+
console.log('\\n3. Token ready for API calls');
|
|
482
|
+
console.log('You can now use this token with ISV JWT authentication');
|
|
483
|
+
} else {
|
|
484
|
+
console.log('✗ Token validation failed');
|
|
485
|
+
}
|
|
486
|
+
} else {
|
|
487
|
+
console.log('✗ Failed to obtain OAuth2 token');
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
} catch (error) {
|
|
491
|
+
console.error('OAuth2 flow error:', error.message);
|
|
492
|
+
}
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
// Run example if this file is executed directly
|
|
496
|
+
if (require.main === module) {
|
|
497
|
+
main().catch(console.error);
|
|
498
|
+
}`;
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
getRequestBodySection(operation, opConfig, merchantPartnerId) {
|
|
502
|
+
if (!opConfig.sampleBody) {
|
|
503
|
+
return '// No request body needed for this operation\n const requestData = new URLSearchParams();';
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
let body = { ...opConfig.sampleBody };
|
|
507
|
+
|
|
508
|
+
// Customize body based on operation
|
|
509
|
+
if (operation === 'obtain_token') {
|
|
510
|
+
body.scope = `merchant:${merchantPartnerId} ${body.scope}`;
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
const bodyEntries = Object.entries(body)
|
|
514
|
+
.map(([key, value]) => {
|
|
515
|
+
if (key === 'client_id') {
|
|
516
|
+
return " requestData.append('client_id', clientId);";
|
|
517
|
+
} else if (key === 'client_secret') {
|
|
518
|
+
return " requestData.append('client_secret', clientSecret);";
|
|
519
|
+
} else {
|
|
520
|
+
return ` requestData.append('${key}', '${value}');`;
|
|
521
|
+
}
|
|
522
|
+
})
|
|
523
|
+
.join('\n');
|
|
524
|
+
|
|
525
|
+
return `// Prepare OAuth2 request data
|
|
526
|
+
const requestData = new URLSearchParams();
|
|
527
|
+
${bodyEntries}`;
|
|
528
|
+
}
|
|
529
|
+
|
|
530
|
+
getRequestSection(method) {
|
|
531
|
+
if (method === 'GET') {
|
|
532
|
+
return 'const response = await axios.get(url, { headers });';
|
|
533
|
+
} else {
|
|
534
|
+
return 'const response = await axios.post(url, requestData, { headers });';
|
|
535
|
+
}
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
getResultProcessingSection(operation) {
|
|
539
|
+
const processing = {
|
|
540
|
+
obtain_token: `// Store token information
|
|
541
|
+
const accessToken = result.access_token;
|
|
542
|
+
const tokenType = result.token_type || 'Bearer';
|
|
543
|
+
const expiresIn = result.expires_in;
|
|
544
|
+
const scope = result.scope;
|
|
545
|
+
|
|
546
|
+
console.log(\`Access Token: \${accessToken.substring(0, 20)}...\`);
|
|
547
|
+
console.log(\`Token Type: \${tokenType}\`);
|
|
548
|
+
console.log(\`Expires In: \${expiresIn} seconds\`);
|
|
549
|
+
console.log(\`Scope: \${scope}\`);
|
|
550
|
+
|
|
551
|
+
// Store token for later use
|
|
552
|
+
process.env.OAUTH2_ACCESS_TOKEN = accessToken;`,
|
|
553
|
+
|
|
554
|
+
get_token_info: `// Display token information
|
|
555
|
+
const active = result.active || false;
|
|
556
|
+
const scope = result.scope || 'N/A';
|
|
557
|
+
const clientId = result.client_id || 'N/A';
|
|
558
|
+
const expiresIn = result.exp || 'N/A';
|
|
559
|
+
|
|
560
|
+
console.log(\`Token Active: \${active}\`);
|
|
561
|
+
console.log(\`Client ID: \${clientId}\`);
|
|
562
|
+
console.log(\`Scope: \${scope}\`);
|
|
563
|
+
console.log(\`Expires: \${expiresIn}\`);`,
|
|
564
|
+
|
|
565
|
+
list_active_tokens: `// Display active tokens
|
|
566
|
+
const tokens = result.tokens || [];
|
|
567
|
+
console.log(\`Found \${tokens.length} active tokens:\`);
|
|
568
|
+
tokens.forEach(token => {
|
|
569
|
+
console.log(\`- Token ID: \${token.id}\`);
|
|
570
|
+
console.log(\` Scope: \${token.scope}\`);
|
|
571
|
+
console.log(\` Created: \${token.created_at}\`);
|
|
572
|
+
console.log(\` Expires: \${token.expires_at}\`);
|
|
573
|
+
});`
|
|
574
|
+
};
|
|
575
|
+
|
|
576
|
+
return processing[operation] || '// Process OAuth2 result as needed';
|
|
577
|
+
}
|
|
578
|
+
}
|
|
579
|
+
|
|
580
|
+
/**
|
|
581
|
+
* Export all generators
|
|
582
|
+
*/
|
|
583
|
+
export const OAuth2Generators = {
|
|
584
|
+
python: PythonOAuth2Generator,
|
|
585
|
+
nodejs: NodeJSOAuth2Generator,
|
|
586
|
+
javascript: NodeJSOAuth2Generator
|
|
587
|
+
};
|
|
588
|
+
|
|
589
|
+
/**
|
|
590
|
+
* Generate OAuth2 example
|
|
591
|
+
*/
|
|
592
|
+
export function generateOAuth2Example(operation, language = 'python', options = {}) {
|
|
593
|
+
const GeneratorClass = OAuth2Generators[language];
|
|
594
|
+
if (!GeneratorClass) {
|
|
595
|
+
throw new Error(`Unsupported language: ${language}`);
|
|
596
|
+
}
|
|
597
|
+
|
|
598
|
+
const generator = new GeneratorClass();
|
|
599
|
+
return generator.generateExample(operation, 'isv', options);
|
|
600
|
+
}
|