@mcp-abap-adt/auth-broker 0.2.10 → 0.2.11
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/CHANGELOG.md +10 -0
- package/README.md +22 -12
- package/bin/mcp-auth.js +49 -0
- package/bin/mcp-auth.ts +654 -0
- package/dist/AuthBroker.d.ts.map +1 -1
- package/dist/AuthBroker.js +15 -3
- package/package.json +8 -7
package/CHANGELOG.md
CHANGED
|
@@ -11,6 +11,16 @@ Thank you to all contributors! See [CONTRIBUTORS.md](CONTRIBUTORS.md) for the co
|
|
|
11
11
|
|
|
12
12
|
## [Unreleased]
|
|
13
13
|
|
|
14
|
+
## [0.2.11] - 2025-12-23
|
|
15
|
+
|
|
16
|
+
### Changed
|
|
17
|
+
- **mcp-auth CLI**: Reworked to use AuthBroker + stores with env-first refresh fallback to service key.
|
|
18
|
+
- **Token provider wiring**: AuthBroker now guards optional token provider methods before invoking them.
|
|
19
|
+
- **Docs**: Added CLI usage details for mcp-auth in README and usage guide.
|
|
20
|
+
|
|
21
|
+
### Updated
|
|
22
|
+
- **Dependencies**: Bumped `@mcp-abap-adt/interfaces` to ^0.2.9 and `@mcp-abap-adt/auth-providers` to latest.
|
|
23
|
+
|
|
14
24
|
## [0.2.10] - 2025-12-22
|
|
15
25
|
|
|
16
26
|
### Changed
|
package/README.md
CHANGED
|
@@ -602,29 +602,39 @@ When UAA credentials are available in session, `AuthBroker` automatically uses d
|
|
|
602
602
|
- If direct UAA request fails and `tokenProvider` is available, broker automatically falls back to provider
|
|
603
603
|
- Provider is useful for browser authentication or alternative authentication flows
|
|
604
604
|
|
|
605
|
-
###
|
|
605
|
+
### CLI: mcp-auth
|
|
606
606
|
|
|
607
|
-
Generate `.env
|
|
607
|
+
Generate or refresh `.env`/JSON output using AuthBroker + stores:
|
|
608
608
|
|
|
609
609
|
```bash
|
|
610
|
-
|
|
610
|
+
mcp-auth --service-key <path> --output <path> [--env <path>] [--type abap|xsuaa] [--browser system|chrome|edge|firefox|none] [--format json|env]
|
|
611
611
|
```
|
|
612
612
|
|
|
613
|
+
**Behavior:**
|
|
614
|
+
- If `--env` is provided and exists, refresh token is attempted first.
|
|
615
|
+
- If refresh fails (or env is missing), service key auth is used.
|
|
616
|
+
- If `--browser` is omitted → client_credentials (no browser).
|
|
617
|
+
- If `--browser` is provided → authorization_code (browser OAuth2).
|
|
618
|
+
|
|
613
619
|
**Examples:**
|
|
614
620
|
```bash
|
|
615
|
-
#
|
|
616
|
-
|
|
621
|
+
# XSUAA: try refresh from env, fallback to service key
|
|
622
|
+
mcp-auth --env ./mcp.env --service-key ./mcp.json --output ./mcp.env --type xsuaa
|
|
617
623
|
|
|
618
|
-
#
|
|
619
|
-
|
|
624
|
+
# ABAP: browser auth (system browser)
|
|
625
|
+
mcp-auth --service-key ./abap.json --output ./abap.env --type abap --browser system
|
|
620
626
|
|
|
621
|
-
#
|
|
622
|
-
|
|
627
|
+
# XSUAA: client_credentials (no browser)
|
|
628
|
+
mcp-auth --service-key ./mcp.json --output ./mcp.env --type xsuaa
|
|
623
629
|
```
|
|
624
630
|
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
631
|
+
### Utility Script
|
|
632
|
+
|
|
633
|
+
Generate `.env` files from service keys:
|
|
634
|
+
|
|
635
|
+
```bash
|
|
636
|
+
npm run generate-env <destination> [service-key-path] [session-path]
|
|
637
|
+
```
|
|
628
638
|
|
|
629
639
|
## Testing
|
|
630
640
|
|
package/bin/mcp-auth.js
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Wrapper script for mcp-auth.ts
|
|
4
|
+
* Uses npx tsx to run TypeScript file
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
const { spawn } = require('child_process');
|
|
8
|
+
const path = require('path');
|
|
9
|
+
const fs = require('fs');
|
|
10
|
+
|
|
11
|
+
// Get absolute path to TypeScript file
|
|
12
|
+
const scriptPath = path.resolve(__dirname, 'mcp-auth.ts');
|
|
13
|
+
|
|
14
|
+
// Check if tsx is available locally, otherwise use npx
|
|
15
|
+
const localTsx = path.join(__dirname, '..', 'node_modules', '.bin', 'tsx');
|
|
16
|
+
const useLocalTsx = fs.existsSync(localTsx);
|
|
17
|
+
|
|
18
|
+
let command;
|
|
19
|
+
let args;
|
|
20
|
+
|
|
21
|
+
if (useLocalTsx) {
|
|
22
|
+
// Use local tsx
|
|
23
|
+
command = process.platform === 'win32' ? `${localTsx}.cmd` : localTsx;
|
|
24
|
+
args = [scriptPath, ...process.argv.slice(2)];
|
|
25
|
+
} else {
|
|
26
|
+
// Use npx tsx
|
|
27
|
+
command = 'npx';
|
|
28
|
+
args = ['tsx', scriptPath, ...process.argv.slice(2)];
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// Run the TypeScript file
|
|
32
|
+
const child = spawn(command, args, {
|
|
33
|
+
stdio: 'inherit',
|
|
34
|
+
shell: false, // Don't use shell to avoid security warnings
|
|
35
|
+
env: process.env,
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
child.on('error', (error) => {
|
|
39
|
+
console.error(`Error: ${error.message}`);
|
|
40
|
+
if (error.code === 'ENOENT') {
|
|
41
|
+
console.error('Please install tsx: npm install -g tsx');
|
|
42
|
+
}
|
|
43
|
+
process.exit(1);
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
child.on('exit', (code) => {
|
|
47
|
+
process.exit(code || 0);
|
|
48
|
+
});
|
|
49
|
+
|
package/bin/mcp-auth.ts
ADDED
|
@@ -0,0 +1,654 @@
|
|
|
1
|
+
#!/usr/bin/env tsx
|
|
2
|
+
/**
|
|
3
|
+
* MCP Auth - Get tokens and generate .env files from service keys
|
|
4
|
+
*
|
|
5
|
+
* Usage:
|
|
6
|
+
* mcp-auth --service-key <path> --output <path> [--env <path>] [--type abap|xsuaa] [--browser none|chrome|edge|firefox|system] [--format json|env]
|
|
7
|
+
*
|
|
8
|
+
* Examples:
|
|
9
|
+
* # Generate .env file (default)
|
|
10
|
+
* mcp-auth --service-key ./service-key.json --output ./mcp.env --type xsuaa --browser none
|
|
11
|
+
* mcp-auth --env ./mcp.env --service-key ./service-key.json --output ./mcp.env --type xsuaa --browser system
|
|
12
|
+
*
|
|
13
|
+
* # Get tokens in JSON format
|
|
14
|
+
* mcp-auth --service-key ./abap-key.json --output ./tokens.json --type abap --browser system --format json
|
|
15
|
+
*
|
|
16
|
+
* # Generate .env file for ABAP
|
|
17
|
+
* mcp-auth --service-key ./abap-key.json --output ./abap.env --type abap --browser system --format env
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
import * as path from 'path';
|
|
21
|
+
import * as fs from 'fs';
|
|
22
|
+
// Use require for CommonJS dist files with absolute path
|
|
23
|
+
const distPath = path.resolve(__dirname, '..', 'dist', 'index.js');
|
|
24
|
+
const { AuthBroker } = require(distPath);
|
|
25
|
+
import {
|
|
26
|
+
AbapServiceKeyStore,
|
|
27
|
+
AbapSessionStore,
|
|
28
|
+
XsuaaServiceKeyStore,
|
|
29
|
+
XsuaaSessionStore,
|
|
30
|
+
} from '@mcp-abap-adt/auth-stores';
|
|
31
|
+
import {
|
|
32
|
+
AuthorizationCodeProvider,
|
|
33
|
+
ClientCredentialsProvider,
|
|
34
|
+
} from '@mcp-abap-adt/auth-providers';
|
|
35
|
+
import type {
|
|
36
|
+
IAuthorizationConfig,
|
|
37
|
+
ITokenProvider,
|
|
38
|
+
ITokenProviderOptions,
|
|
39
|
+
ITokenProviderResult,
|
|
40
|
+
} from '@mcp-abap-adt/interfaces';
|
|
41
|
+
import {
|
|
42
|
+
ABAP_CONNECTION_VARS,
|
|
43
|
+
ABAP_AUTHORIZATION_VARS,
|
|
44
|
+
XSUAA_CONNECTION_VARS,
|
|
45
|
+
XSUAA_AUTHORIZATION_VARS,
|
|
46
|
+
} from '@mcp-abap-adt/auth-stores';
|
|
47
|
+
|
|
48
|
+
interface McpAuthOptions {
|
|
49
|
+
serviceKeyPath?: string; // Optional if env file is provided
|
|
50
|
+
envFilePath?: string;
|
|
51
|
+
outputFile: string;
|
|
52
|
+
authType: 'abap' | 'xsuaa';
|
|
53
|
+
browser?: string; // undefined = client_credentials, any value = browser auth
|
|
54
|
+
format: 'json' | 'env';
|
|
55
|
+
serviceUrl?: string;
|
|
56
|
+
redirectPort?: number; // Port for OAuth redirect URI (default: 3001)
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function getVersion(): string {
|
|
60
|
+
try {
|
|
61
|
+
const packageJsonPath = path.join(__dirname, '..', 'package.json');
|
|
62
|
+
const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'));
|
|
63
|
+
return packageJson.version || 'unknown';
|
|
64
|
+
} catch {
|
|
65
|
+
return 'unknown';
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function showHelp(): void {
|
|
70
|
+
console.log('MCP Auth - Get tokens and generate .env files from service keys');
|
|
71
|
+
console.log('');
|
|
72
|
+
console.log('Usage:');
|
|
73
|
+
console.log(' mcp-auth --service-key <path> --output <path> [options]');
|
|
74
|
+
console.log('');
|
|
75
|
+
console.log('Required Options:');
|
|
76
|
+
console.log(' --output <path> Output file path');
|
|
77
|
+
console.log('');
|
|
78
|
+
console.log('Service Key or Env (one required):');
|
|
79
|
+
console.log(' --service-key <path> Path to service key JSON file');
|
|
80
|
+
console.log(' --env <path> Path to existing .env file (used for refresh token)');
|
|
81
|
+
console.log('');
|
|
82
|
+
console.log('Optional Options:');
|
|
83
|
+
console.log(' --type <type> Auth type: abap or xsuaa (default: abap)');
|
|
84
|
+
console.log(' --browser <browser> Browser auth:');
|
|
85
|
+
console.log(' - none: Show URL and wait for callback (no browser)');
|
|
86
|
+
console.log(' - auto: Try to open browser, fallback to showing URL (like cf login)');
|
|
87
|
+
console.log(' - system/chrome/edge/firefox: Open specific browser');
|
|
88
|
+
console.log(' - headless: Same as none (show URL and wait)');
|
|
89
|
+
console.log(' If not specified: uses client_credentials (clientId/clientSecret)');
|
|
90
|
+
console.log(' --format <format> Output format: json or env (default: env)');
|
|
91
|
+
console.log(' --service-url <url> Service URL (SAP URL for ABAP, MCP URL for XSUAA). For XSUAA, optional.');
|
|
92
|
+
console.log(' --redirect-port <port> Port for OAuth redirect URI (default: 3001). Must match XSUAA redirect-uris config.');
|
|
93
|
+
console.log('');
|
|
94
|
+
console.log(' --version, -v Show version number');
|
|
95
|
+
console.log(' --help, -h Show this help message');
|
|
96
|
+
console.log('');
|
|
97
|
+
console.log('Examples:');
|
|
98
|
+
console.log(' # XSUAA with client_credentials (--browser not specified)');
|
|
99
|
+
console.log(' mcp-auth --service-key ./service-key.json --output ./mcp.env --type xsuaa');
|
|
100
|
+
console.log('');
|
|
101
|
+
console.log(' # XSUAA using existing .env refresh token, fallback to service key');
|
|
102
|
+
console.log(' mcp-auth --env ./mcp.env --service-key ./service-key.json --output ./mcp.env --type xsuaa');
|
|
103
|
+
console.log('');
|
|
104
|
+
console.log(' # XSUAA with browser OAuth2 (show URL, don\'t open browser)');
|
|
105
|
+
console.log(' mcp-auth --service-key ./service-key.json --output ./mcp.env --type xsuaa --browser none');
|
|
106
|
+
console.log('');
|
|
107
|
+
console.log(' # XSUAA with browser OAuth2 (auto - try to open browser, like cf login)');
|
|
108
|
+
console.log(' mcp-auth --service-key ./service-key.json --output ./mcp.env --type xsuaa --browser auto');
|
|
109
|
+
console.log('');
|
|
110
|
+
console.log(' # XSUAA with browser OAuth2 (custom redirect port, e.g., 8080)');
|
|
111
|
+
console.log(' mcp-auth --service-key ./service-key.json --output ./mcp.env --type xsuaa --browser auto --redirect-port 8080');
|
|
112
|
+
console.log('');
|
|
113
|
+
console.log(' # ABAP with client_credentials (--browser not specified)');
|
|
114
|
+
console.log(' mcp-auth --service-key ./abap-key.json --output ./abap.env --type abap');
|
|
115
|
+
console.log('');
|
|
116
|
+
console.log(' # ABAP with browser OAuth2');
|
|
117
|
+
console.log(' mcp-auth --service-key ./abap-key.json --output ./abap.env --type abap --browser system');
|
|
118
|
+
console.log('');
|
|
119
|
+
console.log('Notes:');
|
|
120
|
+
console.log(' - --type determines the provider (xsuaa or abap)');
|
|
121
|
+
console.log(' - If --env is provided and file exists, refresh token is attempted first');
|
|
122
|
+
console.log(' - If refresh fails or env file is missing, service key auth is used');
|
|
123
|
+
console.log(' - Authentication method:');
|
|
124
|
+
console.log(' * --browser NOT specified → client_credentials (clientId/clientSecret, no browser)');
|
|
125
|
+
console.log(' * --browser none/headless → Show URL in console and wait for callback');
|
|
126
|
+
console.log(' * --browser auto → Try to open browser (like cf login), fallback to showing URL');
|
|
127
|
+
console.log(' * --browser system/chrome/edge/firefox → Open specific browser for OAuth2');
|
|
128
|
+
console.log(' - Both providers (xsuaa and abap) support both methods');
|
|
129
|
+
console.log(' - --redirect-port: Port for OAuth redirect URI (default: 3001)');
|
|
130
|
+
console.log(' * Must match redirect_uri configured in XSUAA/ABAP OAuth2 settings');
|
|
131
|
+
console.log(' * Common values: 3001 (default), 8080 (SAP examples)');
|
|
132
|
+
console.log(' - For XSUAA, serviceUrl (MCP URL) is optional - can be provided via --service-url or service key');
|
|
133
|
+
console.log(' - For ABAP, serviceUrl (SAP URL) is required - can be provided via --service-url or service key');
|
|
134
|
+
console.log(' - SAP_URL/XSUAA_MCP_URL is written to .env (from --service-url, service key, or placeholder)');
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
function parseArgs(): McpAuthOptions | null {
|
|
138
|
+
const args = process.argv.slice(2);
|
|
139
|
+
|
|
140
|
+
// Handle --version and --help first
|
|
141
|
+
if (args.length === 0 || args.includes('--help') || args.includes('-h')) {
|
|
142
|
+
showHelp();
|
|
143
|
+
process.exit(0);
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
if (args.includes('--version') || args.includes('-v')) {
|
|
147
|
+
console.log(getVersion());
|
|
148
|
+
process.exit(0);
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
let serviceKeyPath: string | undefined;
|
|
152
|
+
let envFilePath: string | undefined;
|
|
153
|
+
let outputFile: string | undefined;
|
|
154
|
+
let authType: 'abap' | 'xsuaa' = 'abap';
|
|
155
|
+
let browser: string | undefined; // undefined = client_credentials, any value = browser auth
|
|
156
|
+
let format: 'json' | 'env' = 'env';
|
|
157
|
+
let serviceUrl: string | undefined;
|
|
158
|
+
let redirectPort: number | undefined;
|
|
159
|
+
|
|
160
|
+
// Parse arguments
|
|
161
|
+
for (let i = 0; i < args.length; i++) {
|
|
162
|
+
if (args[i] === '--service-key' && i + 1 < args.length) {
|
|
163
|
+
serviceKeyPath = args[i + 1];
|
|
164
|
+
i++;
|
|
165
|
+
} else if (args[i] === '--env' && i + 1 < args.length) {
|
|
166
|
+
envFilePath = args[i + 1];
|
|
167
|
+
i++;
|
|
168
|
+
} else if (args[i] === '--output' && i + 1 < args.length) {
|
|
169
|
+
outputFile = args[i + 1];
|
|
170
|
+
i++;
|
|
171
|
+
} else if (args[i] === '--type' && i + 1 < args.length) {
|
|
172
|
+
const type = args[i + 1];
|
|
173
|
+
if (type === 'abap' || type === 'xsuaa') {
|
|
174
|
+
authType = type;
|
|
175
|
+
} else {
|
|
176
|
+
console.error(`Invalid auth type: ${type}. Must be 'abap' or 'xsuaa'`);
|
|
177
|
+
process.exit(1);
|
|
178
|
+
}
|
|
179
|
+
i++;
|
|
180
|
+
} else if (args[i] === '--browser' && i + 1 < args.length) {
|
|
181
|
+
browser = args[i + 1];
|
|
182
|
+
if (!['none', 'chrome', 'edge', 'firefox', 'system', 'headless', 'auto'].includes(browser)) {
|
|
183
|
+
console.error(`Invalid browser: ${browser}. Must be one of: none, chrome, edge, firefox, system, headless, auto`);
|
|
184
|
+
process.exit(1);
|
|
185
|
+
}
|
|
186
|
+
i++;
|
|
187
|
+
} else if (args[i] === '--format' && i + 1 < args.length) {
|
|
188
|
+
const fmt = args[i + 1];
|
|
189
|
+
if (fmt === 'json' || fmt === 'env') {
|
|
190
|
+
format = fmt;
|
|
191
|
+
} else {
|
|
192
|
+
console.error(`Invalid format: ${fmt}. Must be 'json' or 'env'`);
|
|
193
|
+
process.exit(1);
|
|
194
|
+
}
|
|
195
|
+
i++;
|
|
196
|
+
} else if (args[i] === '--service-url' && i + 1 < args.length) {
|
|
197
|
+
serviceUrl = args[i + 1];
|
|
198
|
+
i++;
|
|
199
|
+
} else if (args[i] === '--redirect-port' && i + 1 < args.length) {
|
|
200
|
+
const port = parseInt(args[i + 1], 10);
|
|
201
|
+
if (isNaN(port) || port < 1 || port > 65535) {
|
|
202
|
+
console.error(`Invalid redirect port: ${args[i + 1]}. Must be a number between 1 and 65535`);
|
|
203
|
+
process.exit(1);
|
|
204
|
+
}
|
|
205
|
+
redirectPort = port;
|
|
206
|
+
i++;
|
|
207
|
+
} else {
|
|
208
|
+
console.error(`Unknown option: ${args[i]}`);
|
|
209
|
+
console.error('Run "mcp-auth --help" for usage information');
|
|
210
|
+
process.exit(1);
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
// Validate required arguments
|
|
215
|
+
if (!outputFile) {
|
|
216
|
+
console.error('Error: --output is required');
|
|
217
|
+
console.error('');
|
|
218
|
+
console.error('Usage: mcp-auth --output <path> [--service-key <path> | --env <path>] [options]');
|
|
219
|
+
console.error('Run "mcp-auth --help" for more information');
|
|
220
|
+
process.exit(1);
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
// Either service-key or env must be provided
|
|
224
|
+
if (!serviceKeyPath && !envFilePath) {
|
|
225
|
+
console.error('Error: Either --service-key or --env must be provided');
|
|
226
|
+
console.error('');
|
|
227
|
+
console.error('Usage: mcp-auth --output <path> [--service-key <path> | --env <path>] [options]');
|
|
228
|
+
console.error('Run "mcp-auth --help" for more information');
|
|
229
|
+
process.exit(1);
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
return {
|
|
233
|
+
serviceKeyPath,
|
|
234
|
+
envFilePath,
|
|
235
|
+
outputFile,
|
|
236
|
+
authType,
|
|
237
|
+
browser,
|
|
238
|
+
format,
|
|
239
|
+
serviceUrl,
|
|
240
|
+
redirectPort,
|
|
241
|
+
};
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
type ProviderMode = 'authorization_code' | 'client_credentials';
|
|
245
|
+
|
|
246
|
+
class BrokerTokenProvider implements ITokenProvider {
|
|
247
|
+
private mode: ProviderMode;
|
|
248
|
+
private browser?: string;
|
|
249
|
+
private redirectPort?: number;
|
|
250
|
+
|
|
251
|
+
constructor(mode: ProviderMode, browser?: string, redirectPort?: number) {
|
|
252
|
+
this.mode = mode;
|
|
253
|
+
this.browser = browser;
|
|
254
|
+
this.redirectPort = redirectPort;
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
async getConnectionConfig(
|
|
258
|
+
authConfig: IAuthorizationConfig,
|
|
259
|
+
options?: ITokenProviderOptions,
|
|
260
|
+
): Promise<ITokenProviderResult> {
|
|
261
|
+
return this.getTokenResult(authConfig, options);
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
async refreshTokenFromSession(
|
|
265
|
+
authConfig: IAuthorizationConfig,
|
|
266
|
+
options?: ITokenProviderOptions,
|
|
267
|
+
): Promise<ITokenProviderResult> {
|
|
268
|
+
return this.getTokenResult(authConfig, options);
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
async refreshTokenFromServiceKey(
|
|
272
|
+
authConfig: IAuthorizationConfig,
|
|
273
|
+
options?: ITokenProviderOptions,
|
|
274
|
+
): Promise<ITokenProviderResult> {
|
|
275
|
+
return this.getTokenResult(authConfig, options);
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
private async getTokenResult(
|
|
279
|
+
authConfig: IAuthorizationConfig,
|
|
280
|
+
options?: ITokenProviderOptions,
|
|
281
|
+
): Promise<ITokenProviderResult> {
|
|
282
|
+
const uaaUrl = authConfig.uaaUrl;
|
|
283
|
+
const uaaClientId = authConfig.uaaClientId;
|
|
284
|
+
const uaaClientSecret = authConfig.uaaClientSecret;
|
|
285
|
+
|
|
286
|
+
if (!uaaUrl || !uaaClientId || !uaaClientSecret) {
|
|
287
|
+
throw new Error('Auth config missing required UAA credentials');
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
if (this.mode === 'client_credentials') {
|
|
291
|
+
const provider = new ClientCredentialsProvider({
|
|
292
|
+
uaaUrl,
|
|
293
|
+
clientId: uaaClientId,
|
|
294
|
+
clientSecret: uaaClientSecret,
|
|
295
|
+
});
|
|
296
|
+
const result = await provider.getTokens();
|
|
297
|
+
return {
|
|
298
|
+
connectionConfig: {
|
|
299
|
+
authorizationToken: result.authorizationToken,
|
|
300
|
+
},
|
|
301
|
+
refreshToken: result.refreshToken,
|
|
302
|
+
};
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
const browserValue = options?.browser ?? this.browser ?? 'system';
|
|
306
|
+
const provider = new AuthorizationCodeProvider({
|
|
307
|
+
uaaUrl,
|
|
308
|
+
clientId: uaaClientId,
|
|
309
|
+
clientSecret: uaaClientSecret,
|
|
310
|
+
refreshToken: authConfig.refreshToken,
|
|
311
|
+
browser: browserValue,
|
|
312
|
+
redirectPort: this.redirectPort,
|
|
313
|
+
});
|
|
314
|
+
const result = await provider.getTokens();
|
|
315
|
+
return {
|
|
316
|
+
connectionConfig: {
|
|
317
|
+
authorizationToken: result.authorizationToken,
|
|
318
|
+
},
|
|
319
|
+
refreshToken: result.refreshToken,
|
|
320
|
+
};
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
function writeEnvFile(
|
|
325
|
+
outputPath: string,
|
|
326
|
+
authType: 'abap' | 'xsuaa',
|
|
327
|
+
token: string,
|
|
328
|
+
refreshToken?: string,
|
|
329
|
+
serviceUrl?: string,
|
|
330
|
+
uaaUrl?: string,
|
|
331
|
+
uaaClientId?: string,
|
|
332
|
+
uaaClientSecret?: string,
|
|
333
|
+
): void {
|
|
334
|
+
const lines: string[] = [];
|
|
335
|
+
|
|
336
|
+
if (authType === 'abap') {
|
|
337
|
+
// ABAP format
|
|
338
|
+
if (serviceUrl) {
|
|
339
|
+
lines.push(`${ABAP_CONNECTION_VARS.SERVICE_URL}=${serviceUrl}`);
|
|
340
|
+
}
|
|
341
|
+
lines.push(`${ABAP_CONNECTION_VARS.AUTHORIZATION_TOKEN}=${token}`);
|
|
342
|
+
|
|
343
|
+
if (refreshToken) {
|
|
344
|
+
lines.push(`${ABAP_AUTHORIZATION_VARS.REFRESH_TOKEN}=${refreshToken}`);
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
if (uaaUrl) {
|
|
348
|
+
lines.push(`${ABAP_AUTHORIZATION_VARS.UAA_URL}=${uaaUrl}`);
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
if (uaaClientId) {
|
|
352
|
+
lines.push(`${ABAP_AUTHORIZATION_VARS.UAA_CLIENT_ID}=${uaaClientId}`);
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
if (uaaClientSecret) {
|
|
356
|
+
lines.push(`${ABAP_AUTHORIZATION_VARS.UAA_CLIENT_SECRET}=${uaaClientSecret}`);
|
|
357
|
+
}
|
|
358
|
+
} else {
|
|
359
|
+
// XSUAA format
|
|
360
|
+
if (serviceUrl) {
|
|
361
|
+
lines.push(`XSUAA_MCP_URL=${serviceUrl}`);
|
|
362
|
+
}
|
|
363
|
+
lines.push(`${XSUAA_CONNECTION_VARS.AUTHORIZATION_TOKEN}=${token}`);
|
|
364
|
+
|
|
365
|
+
if (refreshToken) {
|
|
366
|
+
lines.push(`${XSUAA_AUTHORIZATION_VARS.REFRESH_TOKEN}=${refreshToken}`);
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
if (uaaUrl) {
|
|
370
|
+
lines.push(`${XSUAA_AUTHORIZATION_VARS.UAA_URL}=${uaaUrl}`);
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
if (uaaClientId) {
|
|
374
|
+
lines.push(`${XSUAA_AUTHORIZATION_VARS.UAA_CLIENT_ID}=${uaaClientId}`);
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
if (uaaClientSecret) {
|
|
378
|
+
lines.push(`${XSUAA_AUTHORIZATION_VARS.UAA_CLIENT_SECRET}=${uaaClientSecret}`);
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
// Ensure output directory exists
|
|
383
|
+
const outputDir = path.dirname(outputPath);
|
|
384
|
+
if (!fs.existsSync(outputDir)) {
|
|
385
|
+
fs.mkdirSync(outputDir, { recursive: true });
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
// Write to file
|
|
389
|
+
fs.writeFileSync(outputPath, lines.join('\n') + '\n', 'utf8');
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
function writeJsonFile(
|
|
393
|
+
outputPath: string,
|
|
394
|
+
token: string,
|
|
395
|
+
refreshToken?: string,
|
|
396
|
+
serviceUrl?: string,
|
|
397
|
+
uaaUrl?: string,
|
|
398
|
+
uaaClientId?: string,
|
|
399
|
+
uaaClientSecret?: string,
|
|
400
|
+
): void {
|
|
401
|
+
const outputData: Record<string, string> = {
|
|
402
|
+
accessToken: token,
|
|
403
|
+
};
|
|
404
|
+
|
|
405
|
+
if (refreshToken) {
|
|
406
|
+
outputData.refreshToken = refreshToken;
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
if (serviceUrl) {
|
|
410
|
+
outputData.serviceUrl = serviceUrl;
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
if (uaaUrl) {
|
|
414
|
+
outputData.uaaUrl = uaaUrl;
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
if (uaaClientId) {
|
|
418
|
+
outputData.uaaClientId = uaaClientId;
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
if (uaaClientSecret) {
|
|
422
|
+
outputData.uaaClientSecret = uaaClientSecret;
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
// Ensure output directory exists
|
|
426
|
+
const outputDir = path.dirname(outputPath);
|
|
427
|
+
if (!fs.existsSync(outputDir)) {
|
|
428
|
+
fs.mkdirSync(outputDir, { recursive: true });
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
// Write to file
|
|
432
|
+
fs.writeFileSync(outputPath, JSON.stringify(outputData, null, 2), 'utf8');
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
async function main() {
|
|
436
|
+
const options = parseArgs();
|
|
437
|
+
|
|
438
|
+
if (!options) {
|
|
439
|
+
// Help or version was shown, exit already handled
|
|
440
|
+
return;
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
// Resolve paths
|
|
444
|
+
const resolvedOutputPath = path.resolve(options.outputFile);
|
|
445
|
+
const resolvedEnvPath = options.envFilePath
|
|
446
|
+
? path.resolve(options.envFilePath)
|
|
447
|
+
: undefined;
|
|
448
|
+
|
|
449
|
+
// If service key is provided, use it; optionally read session from env
|
|
450
|
+
let serviceKeyStore: any = null;
|
|
451
|
+
let destination: string | undefined;
|
|
452
|
+
const envExists = resolvedEnvPath ? fs.existsSync(resolvedEnvPath) : false;
|
|
453
|
+
|
|
454
|
+
if (resolvedEnvPath) {
|
|
455
|
+
destination = path.basename(resolvedEnvPath, path.extname(resolvedEnvPath));
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
if (options.serviceKeyPath) {
|
|
459
|
+
const resolvedServiceKeyPath = path.resolve(options.serviceKeyPath);
|
|
460
|
+
const serviceKeyDir = path.dirname(resolvedServiceKeyPath);
|
|
461
|
+
|
|
462
|
+
// Check if service key file exists
|
|
463
|
+
if (!fs.existsSync(resolvedServiceKeyPath)) {
|
|
464
|
+
console.error(`❌ Service key file not found: ${resolvedServiceKeyPath}`);
|
|
465
|
+
process.exit(1);
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
const serviceKeyFileName = path.basename(resolvedServiceKeyPath, '.json');
|
|
469
|
+
if (destination && destination !== serviceKeyFileName) {
|
|
470
|
+
console.error(
|
|
471
|
+
`❌ Destination mismatch: env file (${destination}) vs service key (${serviceKeyFileName})`,
|
|
472
|
+
);
|
|
473
|
+
process.exit(1);
|
|
474
|
+
}
|
|
475
|
+
destination = serviceKeyFileName;
|
|
476
|
+
|
|
477
|
+
// Create appropriate stores based on auth type
|
|
478
|
+
serviceKeyStore = options.authType === 'xsuaa'
|
|
479
|
+
? new XsuaaServiceKeyStore(serviceKeyDir)
|
|
480
|
+
: new AbapServiceKeyStore(serviceKeyDir);
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
if (!destination) {
|
|
484
|
+
console.error('❌ Destination could not be determined from inputs');
|
|
485
|
+
process.exit(1);
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
console.log(`📁 Output file: ${resolvedOutputPath}`);
|
|
489
|
+
if (resolvedEnvPath) {
|
|
490
|
+
console.log(`📁 Env file: ${resolvedEnvPath} (${envExists ? 'found' : 'not found'})`);
|
|
491
|
+
}
|
|
492
|
+
if (options.serviceKeyPath) {
|
|
493
|
+
console.log(`📁 Service key: ${path.resolve(options.serviceKeyPath)}`);
|
|
494
|
+
}
|
|
495
|
+
console.log(`🔐 Auth type: ${options.authType}`);
|
|
496
|
+
console.log(`🌐 Browser: ${options.browser || 'none (client_credentials)'}`);
|
|
497
|
+
console.log(`📄 Format: ${options.format}`);
|
|
498
|
+
if (options.serviceUrl) {
|
|
499
|
+
console.log(`🔗 Service URL: ${options.serviceUrl}`);
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
try {
|
|
503
|
+
if (!envExists && !serviceKeyStore) {
|
|
504
|
+
throw new Error('Env file not found and no service key provided.');
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
// Create temporary session store (work off a temp copy of env file)
|
|
508
|
+
const tempSessionDir = path.join(path.dirname(resolvedOutputPath), '.tmp');
|
|
509
|
+
if (!fs.existsSync(tempSessionDir)) {
|
|
510
|
+
fs.mkdirSync(tempSessionDir, { recursive: true });
|
|
511
|
+
}
|
|
512
|
+
if (envExists && resolvedEnvPath) {
|
|
513
|
+
const tempEnvPath = path.join(tempSessionDir, `${destination}.env`);
|
|
514
|
+
fs.copyFileSync(resolvedEnvPath, tempEnvPath);
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
// Resolve serviceUrl from service key if not provided explicitly
|
|
518
|
+
let actualServiceUrl = options.serviceUrl;
|
|
519
|
+
if (!actualServiceUrl && serviceKeyStore) {
|
|
520
|
+
const serviceKeyConn = await serviceKeyStore.getConnectionConfig(
|
|
521
|
+
destination,
|
|
522
|
+
);
|
|
523
|
+
actualServiceUrl = serviceKeyConn?.serviceUrl;
|
|
524
|
+
}
|
|
525
|
+
|
|
526
|
+
// For XSUAA, serviceUrl is optional - use placeholder only for AuthBroker internal work
|
|
527
|
+
const brokerServiceUrl = actualServiceUrl || '<SERVICE_URL>';
|
|
528
|
+
|
|
529
|
+
const sessionStore =
|
|
530
|
+
options.authType === 'xsuaa'
|
|
531
|
+
? new XsuaaSessionStore(tempSessionDir, brokerServiceUrl)
|
|
532
|
+
: new AbapSessionStore(tempSessionDir);
|
|
533
|
+
|
|
534
|
+
const useBrowserAuth = options.browser !== undefined;
|
|
535
|
+
const providerMode: ProviderMode = useBrowserAuth
|
|
536
|
+
? 'authorization_code'
|
|
537
|
+
: 'client_credentials';
|
|
538
|
+
const tokenProvider = new BrokerTokenProvider(
|
|
539
|
+
providerMode,
|
|
540
|
+
options.browser,
|
|
541
|
+
options.redirectPort,
|
|
542
|
+
);
|
|
543
|
+
|
|
544
|
+
const broker = new AuthBroker(
|
|
545
|
+
{
|
|
546
|
+
sessionStore,
|
|
547
|
+
serviceKeyStore: serviceKeyStore || undefined,
|
|
548
|
+
tokenProvider,
|
|
549
|
+
},
|
|
550
|
+
options.browser,
|
|
551
|
+
);
|
|
552
|
+
|
|
553
|
+
console.log(`🔐 Getting token for destination "${destination}"...`);
|
|
554
|
+
const token = await broker.getToken(destination);
|
|
555
|
+
console.log(`✅ Token obtained successfully`);
|
|
556
|
+
|
|
557
|
+
const connConfig = await sessionStore.getConnectionConfig(destination);
|
|
558
|
+
const authConfig = await sessionStore.getAuthorizationConfig(destination);
|
|
559
|
+
|
|
560
|
+
if (!token) {
|
|
561
|
+
throw new Error(
|
|
562
|
+
`Token provider did not return authorization token for destination "${destination}"`,
|
|
563
|
+
);
|
|
564
|
+
}
|
|
565
|
+
|
|
566
|
+
const outputServiceUrl =
|
|
567
|
+
options.serviceUrl || connConfig?.serviceUrl || actualServiceUrl;
|
|
568
|
+
|
|
569
|
+
// Write output file based on format
|
|
570
|
+
if (options.format === 'env') {
|
|
571
|
+
writeEnvFile(
|
|
572
|
+
resolvedOutputPath,
|
|
573
|
+
options.authType,
|
|
574
|
+
token,
|
|
575
|
+
authConfig?.refreshToken,
|
|
576
|
+
outputServiceUrl,
|
|
577
|
+
authConfig?.uaaUrl,
|
|
578
|
+
authConfig?.uaaClientId,
|
|
579
|
+
authConfig?.uaaClientSecret,
|
|
580
|
+
);
|
|
581
|
+
|
|
582
|
+
console.log(`✅ .env file created: ${resolvedOutputPath}`);
|
|
583
|
+
|
|
584
|
+
// Show what was written
|
|
585
|
+
console.log(`📋 .env file contains:`);
|
|
586
|
+
if (options.authType === 'abap') {
|
|
587
|
+
if (outputServiceUrl) {
|
|
588
|
+
console.log(` - ${ABAP_CONNECTION_VARS.SERVICE_URL}=${outputServiceUrl}`);
|
|
589
|
+
}
|
|
590
|
+
console.log(
|
|
591
|
+
` - ${ABAP_CONNECTION_VARS.AUTHORIZATION_TOKEN}=${token.substring(0, 50)}...`,
|
|
592
|
+
);
|
|
593
|
+
if (authConfig?.refreshToken) {
|
|
594
|
+
console.log(
|
|
595
|
+
` - ${ABAP_AUTHORIZATION_VARS.REFRESH_TOKEN}=${authConfig.refreshToken.substring(0, 50)}...`,
|
|
596
|
+
);
|
|
597
|
+
}
|
|
598
|
+
} else {
|
|
599
|
+
if (outputServiceUrl) {
|
|
600
|
+
console.log(` - XSUAA_MCP_URL=${outputServiceUrl}`);
|
|
601
|
+
}
|
|
602
|
+
console.log(
|
|
603
|
+
` - ${XSUAA_CONNECTION_VARS.AUTHORIZATION_TOKEN}=${token.substring(0, 50)}...`,
|
|
604
|
+
);
|
|
605
|
+
if (authConfig?.refreshToken) {
|
|
606
|
+
console.log(
|
|
607
|
+
` - ${XSUAA_AUTHORIZATION_VARS.REFRESH_TOKEN}=${authConfig.refreshToken.substring(0, 50)}...`,
|
|
608
|
+
);
|
|
609
|
+
}
|
|
610
|
+
}
|
|
611
|
+
} else {
|
|
612
|
+
writeJsonFile(
|
|
613
|
+
resolvedOutputPath,
|
|
614
|
+
token,
|
|
615
|
+
authConfig?.refreshToken,
|
|
616
|
+
outputServiceUrl,
|
|
617
|
+
authConfig?.uaaUrl,
|
|
618
|
+
authConfig?.uaaClientId,
|
|
619
|
+
authConfig?.uaaClientSecret,
|
|
620
|
+
);
|
|
621
|
+
|
|
622
|
+
console.log(`✅ JSON file created: ${resolvedOutputPath}`);
|
|
623
|
+
console.log(`📋 Output contains:`);
|
|
624
|
+
console.log(` - accessToken: ${token.substring(0, 50)}...`);
|
|
625
|
+
if (authConfig?.refreshToken) {
|
|
626
|
+
console.log(
|
|
627
|
+
` - refreshToken: ${authConfig.refreshToken.substring(0, 50)}...`,
|
|
628
|
+
);
|
|
629
|
+
}
|
|
630
|
+
if (outputServiceUrl) {
|
|
631
|
+
console.log(` - serviceUrl: ${outputServiceUrl}`);
|
|
632
|
+
}
|
|
633
|
+
}
|
|
634
|
+
|
|
635
|
+
// Cleanup temp directory
|
|
636
|
+
try {
|
|
637
|
+
fs.rmSync(tempSessionDir, { recursive: true, force: true });
|
|
638
|
+
} catch {
|
|
639
|
+
// Ignore cleanup errors
|
|
640
|
+
}
|
|
641
|
+
|
|
642
|
+
} catch (error: any) {
|
|
643
|
+
console.error(`❌ Error: ${error.message}`);
|
|
644
|
+
if (error.stack) {
|
|
645
|
+
console.error(error.stack);
|
|
646
|
+
}
|
|
647
|
+
process.exit(1);
|
|
648
|
+
}
|
|
649
|
+
}
|
|
650
|
+
|
|
651
|
+
main().catch((error) => {
|
|
652
|
+
console.error('Fatal error:', error);
|
|
653
|
+
process.exit(1);
|
|
654
|
+
});
|
package/dist/AuthBroker.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AuthBroker.d.ts","sourceRoot":"","sources":["../src/AuthBroker.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EACL,KAAK,OAAO,EACZ,KAAK,eAAe,EAErB,MAAM,0BAA0B,CAAC;AAClC,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAClD,OAAO,KAAK,EACV,oBAAoB,EACpB,iBAAiB,EACjB,gBAAgB,EAChB,aAAa,EACd,MAAM,qBAAqB,CAAC;AA4C7B;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,mEAAmE;IACnE,YAAY,EAAE,aAAa,CAAC;IAC5B,uEAAuE;IACvE,eAAe,CAAC,EAAE,gBAAgB,CAAC;IACnC,4IAA4I;IAC5I,aAAa,EAAE,cAAc,CAAC;IAC9B;;;;OAIG;IACH,gBAAgB,CAAC,EAAE,OAAO,CAAC;CAC5B;AAED;;GAEG;AACH,qBAAa,UAAU;IACrB,OAAO,CAAC,OAAO,CAAqB;IACpC,OAAO,CAAC,MAAM,CAAU;IACxB,OAAO,CAAC,eAAe,CAA+B;IACtD,OAAO,CAAC,YAAY,CAAgB;IACpC,OAAO,CAAC,aAAa,CAAiB;IACtC,OAAO,CAAC,gBAAgB,CAAU;IAElC;;;;;;;;;;;OAWG;gBACS,MAAM,EAAE,gBAAgB,EAAE,OAAO,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,OAAO;IAoFxE;;OAEG;YACW,eAAe;IA0D7B;;OAEG;YACW,aAAa;IAoD3B;;OAEG;YACW,iBAAiB;IA2D/B;;OAEG;YACW,kBAAkB;IAkChC;;OAEG;YACW,+BAA+B;
|
|
1
|
+
{"version":3,"file":"AuthBroker.d.ts","sourceRoot":"","sources":["../src/AuthBroker.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EACL,KAAK,OAAO,EACZ,KAAK,eAAe,EAErB,MAAM,0BAA0B,CAAC;AAClC,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAClD,OAAO,KAAK,EACV,oBAAoB,EACpB,iBAAiB,EACjB,gBAAgB,EAChB,aAAa,EACd,MAAM,qBAAqB,CAAC;AA4C7B;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,mEAAmE;IACnE,YAAY,EAAE,aAAa,CAAC;IAC5B,uEAAuE;IACvE,eAAe,CAAC,EAAE,gBAAgB,CAAC;IACnC,4IAA4I;IAC5I,aAAa,EAAE,cAAc,CAAC;IAC9B;;;;OAIG;IACH,gBAAgB,CAAC,EAAE,OAAO,CAAC;CAC5B;AAED;;GAEG;AACH,qBAAa,UAAU;IACrB,OAAO,CAAC,OAAO,CAAqB;IACpC,OAAO,CAAC,MAAM,CAAU;IACxB,OAAO,CAAC,eAAe,CAA+B;IACtD,OAAO,CAAC,YAAY,CAAgB;IACpC,OAAO,CAAC,aAAa,CAAiB;IACtC,OAAO,CAAC,gBAAgB,CAAU;IAElC;;;;;;;;;;;OAWG;gBACS,MAAM,EAAE,gBAAgB,EAAE,OAAO,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,OAAO;IAoFxE;;OAEG;YACW,eAAe;IA0D7B;;OAEG;YACW,aAAa;IAoD3B;;OAEG;YACW,iBAAiB;IA2D/B;;OAEG;YACW,kBAAkB;IAkChC;;OAEG;YACW,+BAA+B;IA4G7C;;OAEG;YACW,qBAAqB;IA8BnC;;OAEG;YACW,uBAAuB;IAyFrC;;OAEG;YACW,0BAA0B;IAgHxC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAuCG;IACG,QAAQ,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IA8GpD;;;;;OAKG;IACG,YAAY,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IASxD;;;;OAIG;IACG,sBAAsB,CAC1B,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC,oBAAoB,GAAG,IAAI,CAAC;IAoEvC;;;;OAIG;IACG,mBAAmB,CACvB,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC,iBAAiB,GAAG,IAAI,CAAC;IA8DpC;;;;;;;;;;;;;;;;OAgBG;IACH,oBAAoB,CAAC,WAAW,EAAE,MAAM,GAAG,eAAe;CAqB3D"}
|
package/dist/AuthBroker.js
CHANGED
|
@@ -276,9 +276,13 @@ class AuthBroker {
|
|
|
276
276
|
throw error;
|
|
277
277
|
}
|
|
278
278
|
this.logger?.debug(`Step 0: Authenticating via provider (browser) for ${destination} using service key UAA credentials`);
|
|
279
|
+
const getConnectionConfig = this.tokenProvider.getConnectionConfig;
|
|
280
|
+
if (!getConnectionConfig) {
|
|
281
|
+
throw new Error('AuthBroker: tokenProvider.getConnectionConfig is required');
|
|
282
|
+
}
|
|
279
283
|
let tokenResult;
|
|
280
284
|
try {
|
|
281
|
-
tokenResult = await
|
|
285
|
+
tokenResult = await getConnectionConfig(serviceKeyAuthConfig, {
|
|
282
286
|
browser: this.browser,
|
|
283
287
|
logger: this.logger,
|
|
284
288
|
});
|
|
@@ -347,9 +351,13 @@ class AuthBroker {
|
|
|
347
351
|
async refreshTokenFromSession(destination, uaaCredentials, refreshToken, serviceUrl) {
|
|
348
352
|
this.logger?.debug(`Step 2a: Trying refreshTokenFromSession for ${destination}`);
|
|
349
353
|
const authConfigWithRefresh = { ...uaaCredentials, refreshToken };
|
|
354
|
+
const refreshTokenFromSession = this.tokenProvider.refreshTokenFromSession;
|
|
355
|
+
if (!refreshTokenFromSession) {
|
|
356
|
+
throw new Error('AuthBroker: tokenProvider.refreshTokenFromSession is required');
|
|
357
|
+
}
|
|
350
358
|
let tokenResult;
|
|
351
359
|
try {
|
|
352
|
-
tokenResult = await
|
|
360
|
+
tokenResult = await refreshTokenFromSession(authConfigWithRefresh, {
|
|
353
361
|
browser: this.browser,
|
|
354
362
|
logger: this.logger,
|
|
355
363
|
});
|
|
@@ -408,9 +416,13 @@ class AuthBroker {
|
|
|
408
416
|
throw error;
|
|
409
417
|
}
|
|
410
418
|
this.logger?.debug(`Step 2b: Trying refreshTokenFromServiceKey for ${destination}`);
|
|
419
|
+
const refreshTokenFromServiceKey = this.tokenProvider.refreshTokenFromServiceKey;
|
|
420
|
+
if (!refreshTokenFromServiceKey) {
|
|
421
|
+
throw new Error('AuthBroker: tokenProvider.refreshTokenFromServiceKey is required');
|
|
422
|
+
}
|
|
411
423
|
let tokenResult;
|
|
412
424
|
try {
|
|
413
|
-
tokenResult = await
|
|
425
|
+
tokenResult = await refreshTokenFromServiceKey(uaaCredentials, {
|
|
414
426
|
browser: this.browser,
|
|
415
427
|
logger: this.logger,
|
|
416
428
|
});
|
package/package.json
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mcp-abap-adt/auth-broker",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.11",
|
|
4
4
|
"description": "JWT authentication broker for MCP ABAP ADT - manages tokens based on destination headers",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
7
7
|
"files": [
|
|
8
8
|
"dist",
|
|
9
|
+
"bin",
|
|
9
10
|
"README.md",
|
|
10
11
|
"CHANGELOG.md",
|
|
11
12
|
"CONTRIBUTORS.md",
|
|
@@ -49,19 +50,20 @@
|
|
|
49
50
|
"generate-env": "tsx bin/generate-env-from-service-key.ts"
|
|
50
51
|
},
|
|
51
52
|
"bin": {
|
|
52
|
-
"
|
|
53
|
+
"mcp-auth": "./bin/mcp-auth.js"
|
|
53
54
|
},
|
|
54
55
|
"engines": {
|
|
55
56
|
"node": ">=18.0.0"
|
|
56
57
|
},
|
|
57
58
|
"dependencies": {
|
|
58
|
-
"@mcp-abap-adt/
|
|
59
|
-
"
|
|
59
|
+
"@mcp-abap-adt/auth-providers": "^0.2.6",
|
|
60
|
+
"@mcp-abap-adt/auth-stores": "^0.2.8",
|
|
61
|
+
"@mcp-abap-adt/interfaces": "^0.2.9",
|
|
62
|
+
"axios": "^1.13.2",
|
|
63
|
+
"tsx": "^4.21.0"
|
|
60
64
|
},
|
|
61
65
|
"devDependencies": {
|
|
62
66
|
"@biomejs/biome": "^2.3.10",
|
|
63
|
-
"@mcp-abap-adt/auth-providers": "^0.2.4",
|
|
64
|
-
"@mcp-abap-adt/auth-stores": "^0.2.8",
|
|
65
67
|
"@types/express": "^5.0.5",
|
|
66
68
|
"@types/jest": "^30.0.0",
|
|
67
69
|
"@types/js-yaml": "^4.0.9",
|
|
@@ -70,7 +72,6 @@
|
|
|
70
72
|
"jest-util": "^30.2.0",
|
|
71
73
|
"js-yaml": "^4.1.1",
|
|
72
74
|
"ts-jest": "^29.2.5",
|
|
73
|
-
"tsx": "^4.21.0",
|
|
74
75
|
"typescript": "^5.9.2"
|
|
75
76
|
}
|
|
76
77
|
}
|