@mcp-abap-adt/auth-providers 0.1.2 → 0.1.4

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 CHANGED
@@ -7,6 +7,59 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [0.1.4] - 2025-12-08
11
+
12
+ ### Added
13
+ - **Integration Tests for browserAuth**: Added real integration test that uses actual service keys and OAuth flow
14
+ - Test verifies token retrieval with real credentials from service keys
15
+ - Shows all authentication stages with logging when `DEBUG_AUTH_PROVIDERS=true` is set
16
+ - Tests both access token and refresh token retrieval
17
+ - **Test Logger Helper**: Added `createTestLogger` helper for tests with environment variable control
18
+ - Supports log levels (debug, info, warn, error) via `LOG_LEVEL` environment variable
19
+ - Only outputs logs when `DEBUG_AUTH_PROVIDERS=true` or `DEBUG_BROWSER_AUTH=true` is set
20
+ - Provides clean, controlled logging for test scenarios
21
+
22
+ ### Changed
23
+ - **Improved Logging in browserAuth**: Made logging more concise and informative
24
+ - All log messages are now single-line strings without verbose objects
25
+ - Logs show key information: what we send, what we receive, token lengths
26
+ - Example: `Tokens received: accessToken(2263 chars), refreshToken(34 chars)`
27
+ - Logging only works when logger is provided (no default console output)
28
+ - **exchangeCodeForToken Function**: Exported for testing purposes
29
+ - Function is marked as `@internal` but exported to enable unit testing
30
+ - Allows testing token exchange logic without full browser auth flow
31
+
32
+ ### Fixed
33
+ - **Test Error Logging**: Fixed error test to use mock logger without console output
34
+ - Error test no longer pollutes console with error messages
35
+ - Still verifies that error logging occurs via spy
36
+
37
+ ## [0.1.3] - 2025-12-07
38
+
39
+ ### Added
40
+ - **Configurable Browser Auth Port**: Added optional `browserAuthPort` parameter to `BtpTokenProvider` constructor
41
+ - Allows configuring the OAuth callback server port (default: 3001)
42
+ - Prevents port conflicts when proxy server runs on the same port
43
+ - Port is passed through to `startBrowserAuth` and `exchangeCodeForToken` functions
44
+ - Enables proxy to configure browser auth port via CLI parameter or YAML config
45
+
46
+ ### Changed
47
+ - **BtpTokenProvider Constructor**: Now accepts optional `browserAuthPort?: number` parameter
48
+ - Defaults to 3001 if not specified (maintains backward compatibility)
49
+ - **startBrowserAuth Function**: Added optional `port: number = 3001` parameter
50
+ - Port is used for OAuth callback server and redirect URI
51
+ - **exchangeCodeForToken Function**: Added optional `port: number = 3001` parameter
52
+ - Port is used in redirect URI when exchanging authorization code for tokens
53
+ - **Implementation Isolation**: Internal authentication functions are no longer exported from package
54
+ - `startBrowserAuth`, `refreshJwtToken`, and `getTokenWithClientCredentials` are now internal functions
55
+ - Providers use private method wrappers to call these functions
56
+ - Constructor parameters (like `browserAuthPort`) are passed through private methods to internal functions
57
+ - This ensures proper encapsulation and prevents direct usage of internal implementation details
58
+ - **Test Improvements**: Unit tests now use provider methods instead of direct internal function imports
59
+ - Tests use `jest.spyOn` to mock private provider methods instead of mocking internal functions
60
+ - Tests now properly test the public API of providers, ensuring better isolation
61
+ - This aligns with encapsulation principles and makes tests more maintainable
62
+
10
63
  ## [0.1.2] - 2025-12-05
11
64
 
12
65
  ### Changed
package/README.md CHANGED
@@ -130,10 +130,11 @@ const btpBroker = new AuthBroker({
130
130
  const abapServiceKeyStore = new AbapServiceKeyStore('/path/to/service-keys');
131
131
  const abapSessionStore = new AbapSessionStore('/path/to/sessions');
132
132
 
133
+ // Use custom port if running alongside other services (e.g., proxy on port 3001)
133
134
  const abapBroker = new AuthBroker({
134
135
  serviceKeyStore: abapServiceKeyStore,
135
136
  sessionStore: abapSessionStore,
136
- tokenProvider: new BtpTokenProvider(), // BtpTokenProvider works for ABAP too
137
+ tokenProvider: new BtpTokenProvider(4001), // Custom port to avoid conflicts
137
138
  });
138
139
  ```
139
140
 
@@ -171,8 +172,12 @@ Uses browser-based OAuth2 flow or refresh token:
171
172
  import { BtpTokenProvider } from '@mcp-abap-adt/auth-providers';
172
173
  import type { IAuthorizationConfig } from '@mcp-abap-adt/auth-broker';
173
174
 
175
+ // Create provider with default port (3001)
174
176
  const provider = new BtpTokenProvider();
175
177
 
178
+ // Or specify custom port for OAuth callback server (useful to avoid port conflicts)
179
+ const providerWithCustomPort = new BtpTokenProvider(4001);
180
+
176
181
  const authConfig: IAuthorizationConfig = {
177
182
  uaaUrl: 'https://...authentication...hana.ondemand.com',
178
183
  uaaClientId: '...',
@@ -191,6 +196,8 @@ const result = await provider.getConnectionConfig(authConfig, {
191
196
  // result.refreshToken contains refresh token (if browser flow was used)
192
197
  ```
193
198
 
199
+ **Note**: The `browserAuthPort` parameter (default: 3001) configures the OAuth callback server port. This is useful when running the provider in environments where port 3001 is already in use (e.g., when running alongside a proxy server).
200
+
194
201
  ### Token Validation
195
202
 
196
203
  Both providers support token validation:
@@ -237,6 +244,32 @@ Integration tests will skip if `test-config.yaml` is not configured or contains
237
244
  - ABAP integration tests use `abap.destination` and require `AbapServiceKeyStore`/`AbapSessionStore` (with `sapUrl`)
238
245
  - BTP/ABAP integration tests may open a browser for authentication if no refresh token is available. This is expected behavior.
239
246
 
247
+ ### Debug Logging
248
+
249
+ To enable detailed logging during tests or runtime, set environment variables:
250
+
251
+ ```bash
252
+ # Enable logging for auth providers
253
+ DEBUG_AUTH_PROVIDERS=true npm test
254
+
255
+ # Or enable browser auth specific logging
256
+ DEBUG_BROWSER_AUTH=true npm test
257
+
258
+ # Set log level (debug, info, warn, error)
259
+ LOG_LEVEL=debug npm test
260
+ ```
261
+
262
+ Logging shows:
263
+ - Token exchange stages (what we send, what we receive)
264
+ - Token information (lengths, previews)
265
+ - Errors with details
266
+
267
+ Example output:
268
+ ```
269
+ [INTEGRATION] Exchanging code for token: https://.../oauth/token
270
+ [INTEGRATION] Tokens received: accessToken(2263 chars), refreshToken(34 chars)
271
+ ```
272
+
240
273
  ## Dependencies
241
274
 
242
275
  - `@mcp-abap-adt/auth-broker` (^0.1.6) - Interface definitions
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Test logger with environment variable control
3
+ */
4
+ import type { ILogger } from '@mcp-abap-adt/interfaces';
5
+ export declare function createTestLogger(prefix?: string): ILogger;
6
+ //# sourceMappingURL=testLogger.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"testLogger.d.ts","sourceRoot":"","sources":["../../../src/__tests__/helpers/testLogger.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,0BAA0B,CAAC;AAgBxD,wBAAgB,gBAAgB,CAAC,MAAM,GAAE,MAAe,GAAG,OAAO,CA4BjE"}
@@ -0,0 +1,44 @@
1
+ "use strict";
2
+ /**
3
+ * Test logger with environment variable control
4
+ */
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.createTestLogger = createTestLogger;
7
+ function getLogLevel() {
8
+ const level = process.env.LOG_LEVEL?.toLowerCase() || 'info';
9
+ const levels = ['debug', 'info', 'warn', 'error'];
10
+ return levels.includes(level) ? level : 'info';
11
+ }
12
+ function shouldLog(level) {
13
+ const currentLevel = getLogLevel();
14
+ const levels = ['debug', 'info', 'warn', 'error'];
15
+ return levels.indexOf(level) >= levels.indexOf(currentLevel);
16
+ }
17
+ function createTestLogger(prefix = 'TEST') {
18
+ const level = getLogLevel();
19
+ const enabled = process.env.DEBUG_AUTH_PROVIDERS === 'true' ||
20
+ process.env.DEBUG_BROWSER_AUTH === 'true' ||
21
+ process.env.DEBUG === 'true';
22
+ return {
23
+ debug: (message, meta) => {
24
+ if (enabled && shouldLog('debug')) {
25
+ console.debug(`[${prefix}] [DEBUG] ${message}`, meta || '');
26
+ }
27
+ },
28
+ info: (message, meta) => {
29
+ if (enabled && shouldLog('info')) {
30
+ console.info(`[${prefix}] ${message}`, meta || '');
31
+ }
32
+ },
33
+ warn: (message, meta) => {
34
+ if (enabled && shouldLog('warn')) {
35
+ console.warn(`[${prefix}] [WARN] ${message}`, meta || '');
36
+ }
37
+ },
38
+ error: (message, meta) => {
39
+ if (enabled && shouldLog('error')) {
40
+ console.error(`[${prefix}] [ERROR] ${message}`, meta || '');
41
+ }
42
+ },
43
+ };
44
+ }
@@ -2,14 +2,24 @@
2
2
  * Browser authentication - OAuth2 flow for obtaining tokens
3
3
  */
4
4
  import type { IAuthorizationConfig, ILogger } from '@mcp-abap-adt/interfaces';
5
+ /**
6
+ * Exchange authorization code for tokens
7
+ * @internal - Exported for testing
8
+ */
9
+ export declare function exchangeCodeForToken(authConfig: IAuthorizationConfig, code: string, port?: number, log?: ILogger | null): Promise<{
10
+ accessToken: string;
11
+ refreshToken?: string;
12
+ }>;
5
13
  /**
6
14
  * Start browser authentication flow
7
15
  * @param authConfig Authorization configuration with UAA credentials
8
16
  * @param browser Browser name (chrome, edge, firefox, system, none)
9
17
  * @param logger Optional logger instance. If not provided, uses default logger.
18
+ * @param port Port for OAuth callback server (default: 3001)
10
19
  * @returns Promise that resolves to tokens
20
+ * @internal - Internal function, not exported from package
11
21
  */
12
- export declare function startBrowserAuth(authConfig: IAuthorizationConfig, browser?: string, logger?: ILogger): Promise<{
22
+ export declare function startBrowserAuth(authConfig: IAuthorizationConfig, browser?: string, logger?: ILogger, port?: number): Promise<{
13
23
  accessToken: string;
14
24
  refreshToken?: string;
15
25
  }>;
@@ -1 +1 @@
1
- {"version":3,"file":"browserAuth.d.ts","sourceRoot":"","sources":["../../src/auth/browserAuth.ts"],"names":[],"mappings":"AAAA;;GAEG;AAMH,OAAO,KAAK,EAAE,oBAAoB,EAAE,OAAO,EAAE,MAAM,0BAA0B,CAAC;AAkF9E;;;;;;GAMG;AACH,wBAAsB,gBAAgB,CACpC,UAAU,EAAE,oBAAoB,EAChC,OAAO,GAAE,MAAiB,EAC1B,MAAM,CAAC,EAAE,OAAO,GACf,OAAO,CAAC;IAAE,WAAW,EAAE,MAAM,CAAC;IAAC,YAAY,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,CAkSzD"}
1
+ {"version":3,"file":"browserAuth.d.ts","sourceRoot":"","sources":["../../src/auth/browserAuth.ts"],"names":[],"mappings":"AAAA;;GAEG;AAMH,OAAO,KAAK,EAAE,oBAAoB,EAAE,OAAO,EAAE,MAAM,0BAA0B,CAAC;AAyB9E;;;GAGG;AACH,wBAAsB,oBAAoB,CACxC,UAAU,EAAE,oBAAoB,EAChC,IAAI,EAAE,MAAM,EACZ,IAAI,GAAE,MAAa,EACnB,GAAG,CAAC,EAAE,OAAO,GAAG,IAAI,GACnB,OAAO,CAAC;IAAE,WAAW,EAAE,MAAM,CAAC;IAAC,YAAY,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,CAsCzD;AAaD;;;;;;;;GAQG;AACH,wBAAsB,gBAAgB,CACpC,UAAU,EAAE,oBAAoB,EAChC,OAAO,GAAE,MAAiB,EAC1B,MAAM,CAAC,EAAE,OAAO,EAChB,IAAI,GAAE,MAAa,GAClB,OAAO,CAAC;IAAE,WAAW,EAAE,MAAM,CAAC;IAAC,YAAY,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,CAuSzD"}
@@ -39,6 +39,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
39
39
  return (mod && mod.__esModule) ? mod : { "default": mod };
40
40
  };
41
41
  Object.defineProperty(exports, "__esModule", { value: true });
42
+ exports.exchangeCodeForToken = exchangeCodeForToken;
42
43
  exports.startBrowserAuth = startBrowserAuth;
43
44
  const http = __importStar(require("http"));
44
45
  const child_process = __importStar(require("child_process"));
@@ -65,16 +66,18 @@ function getJwtAuthorizationUrl(authConfig, port = 3001) {
65
66
  }
66
67
  /**
67
68
  * Exchange authorization code for tokens
69
+ * @internal - Exported for testing
68
70
  */
69
- async function exchangeCodeForToken(authConfig, code) {
71
+ async function exchangeCodeForToken(authConfig, code, port = 3001, log) {
70
72
  const { uaaUrl: url, uaaClientId: clientid, uaaClientSecret: clientsecret } = authConfig;
71
73
  const tokenUrl = `${url}/oauth/token`;
72
- const redirectUri = 'http://localhost:3001/callback';
74
+ const redirectUri = `http://localhost:${port}/callback`;
73
75
  const params = new URLSearchParams();
74
76
  params.append('grant_type', 'authorization_code');
75
77
  params.append('code', code);
76
78
  params.append('redirect_uri', redirectUri);
77
79
  const authString = Buffer.from(`${clientid}:${clientsecret}`).toString('base64');
80
+ log?.info(`Exchanging code for token: ${tokenUrl}`);
78
81
  const response = await (0, axios_1.default)({
79
82
  method: 'post',
80
83
  url: tokenUrl,
@@ -85,40 +88,41 @@ async function exchangeCodeForToken(authConfig, code) {
85
88
  data: params.toString(),
86
89
  });
87
90
  if (response.data && response.data.access_token) {
91
+ const accessToken = response.data.access_token;
92
+ const refreshToken = response.data.refresh_token;
93
+ log?.info(`Tokens received: accessToken(${accessToken.length} chars), refreshToken(${refreshToken?.length || 0} chars)`);
88
94
  return {
89
- accessToken: response.data.access_token,
90
- refreshToken: response.data.refresh_token,
95
+ accessToken,
96
+ refreshToken,
91
97
  };
92
98
  }
93
99
  else {
100
+ log?.error(`Token exchange failed: status ${response.status}, error: ${response.data?.error || 'unknown'}`);
94
101
  throw new Error('Response does not contain access_token');
95
102
  }
96
103
  }
97
104
  /**
98
- * Default logger implementation
105
+ * Check if debug logging is enabled for auth providers
99
106
  */
100
- const defaultLogger = {
101
- info: (msg) => console.info(msg),
102
- debug: (msg) => console.debug(`[DEBUG] ${msg}`),
103
- error: (msg) => console.error(msg),
104
- browserUrl: (url) => console.info(`🔗 Open in browser: ${url}`),
105
- browserOpening: () => console.debug(`🌐 Opening browser for authentication...`),
106
- };
107
+ function isDebugEnabled() {
108
+ return process.env.DEBUG_AUTH_PROVIDERS === 'true' ||
109
+ process.env.DEBUG_BROWSER_AUTH === 'true' ||
110
+ process.env.DEBUG === 'true' ||
111
+ process.env.DEBUG?.includes('auth-providers') === true ||
112
+ process.env.DEBUG?.includes('browser-auth') === true;
113
+ }
107
114
  /**
108
115
  * Start browser authentication flow
109
116
  * @param authConfig Authorization configuration with UAA credentials
110
117
  * @param browser Browser name (chrome, edge, firefox, system, none)
111
118
  * @param logger Optional logger instance. If not provided, uses default logger.
119
+ * @param port Port for OAuth callback server (default: 3001)
112
120
  * @returns Promise that resolves to tokens
121
+ * @internal - Internal function, not exported from package
113
122
  */
114
- async function startBrowserAuth(authConfig, browser = 'system', logger) {
115
- const log = logger ? {
116
- info: (msg) => logger.info(msg),
117
- debug: (msg) => logger.debug(msg),
118
- error: (msg) => logger.error(msg),
119
- browserUrl: (url) => logger.info(`🔗 Open in browser: ${url}`),
120
- browserOpening: () => logger.debug('🌐 Opening browser for authentication...'),
121
- } : defaultLogger;
123
+ async function startBrowserAuth(authConfig, browser = 'system', logger, port = 3001) {
124
+ // Use logger if provided, otherwise null (no logging)
125
+ const log = logger || null;
122
126
  return new Promise((originalResolve, originalReject) => {
123
127
  let timeoutId = null;
124
128
  const resolve = (value) => {
@@ -133,15 +137,18 @@ async function startBrowserAuth(authConfig, browser = 'system', logger) {
133
137
  };
134
138
  const app = (0, express_1.default)();
135
139
  const server = http.createServer(app);
136
- const PORT = 3001;
140
+ const PORT = port;
137
141
  let serverInstance = null;
138
142
  const authorizationUrl = getJwtAuthorizationUrl(authConfig, PORT);
139
143
  // OAuth2 callback handler
140
144
  app.get('/callback', async (req, res) => {
141
145
  try {
146
+ log?.info(`Callback received: ${req.url}`);
147
+ log?.debug(`Callback query: ${JSON.stringify(req.query)}`);
142
148
  // Check for OAuth2 error parameters
143
149
  const { error, error_description, error_uri } = req.query;
144
150
  if (error) {
151
+ log?.error(`Callback error: ${error}${error_description ? ` - ${error_description}` : ''}`);
145
152
  const errorMsg = error_description
146
153
  ? `${error}: ${error_description}`
147
154
  : String(error);
@@ -212,10 +219,13 @@ async function startBrowserAuth(authConfig, browser = 'system', logger) {
212
219
  return reject(new Error(`OAuth2 authentication failed: ${errorMsg}${error_uri ? ` (${error_uri})` : ''}`));
213
220
  }
214
221
  const { code } = req.query;
222
+ log?.debug(`Callback code received: ${code ? 'yes' : 'no'}`);
215
223
  if (!code || typeof code !== 'string') {
224
+ log?.error(`Callback code missing`);
216
225
  res.status(400).send('Error: Authorization code missing');
217
226
  return reject(new Error('Authorization code missing'));
218
227
  }
228
+ log?.debug(`Exchanging code for token`);
219
229
  // Send success page
220
230
  const html = `<!DOCTYPE html>
221
231
  <html lang="en">
@@ -278,7 +288,8 @@ async function startBrowserAuth(authConfig, browser = 'system', logger) {
278
288
  res.send(html);
279
289
  // Exchange code for tokens and close server
280
290
  try {
281
- const tokens = await exchangeCodeForToken(authConfig, code);
291
+ const tokens = await exchangeCodeForToken(authConfig, code, PORT, log);
292
+ log?.info(`Tokens received: accessToken(${tokens.accessToken?.length || 0} chars), refreshToken(${tokens.refreshToken?.length || 0} chars)`);
282
293
  // Close all connections and server immediately after getting tokens
283
294
  if (typeof server.closeAllConnections === 'function') {
284
295
  server.closeAllConnections();
@@ -309,7 +320,7 @@ async function startBrowserAuth(authConfig, browser = 'system', logger) {
309
320
  serverInstance = server.listen(PORT, async () => {
310
321
  const browserApp = BROWSER_MAP[browser];
311
322
  if (!browser || browser === 'none' || browserApp === null) {
312
- log.browserUrl(authorizationUrl);
323
+ log?.info(`🔗 Open in browser: ${authorizationUrl}`, { url: authorizationUrl });
313
324
  // For 'none' browser, don't wait for callback - throw error immediately
314
325
  // User must open browser manually and we can't wait for callback in automated tests
315
326
  if (serverInstance) {
@@ -321,7 +332,7 @@ async function startBrowserAuth(authConfig, browser = 'system', logger) {
321
332
  return;
322
333
  }
323
334
  else {
324
- log.browserOpening();
335
+ log?.debug('🌐 Opening browser for authentication...');
325
336
  try {
326
337
  // Try dynamic import first (for ES modules)
327
338
  let open;
@@ -366,7 +377,7 @@ async function startBrowserAuth(authConfig, browser = 'system', logger) {
366
377
  // Use child_process as fallback (non-blocking)
367
378
  child_process.exec(`${command} "${authorizationUrl}"`, (error) => {
368
379
  if (error) {
369
- log.error(`❌ Failed to open browser: ${error.message}. Please open manually: ${authorizationUrl}`);
380
+ log?.error(`❌ Failed to open browser: ${error.message}. Please open manually: ${authorizationUrl}`, { error: error.message, url: authorizationUrl });
370
381
  }
371
382
  });
372
383
  return; // Exit early since we're using child_process (non-blocking)
@@ -381,8 +392,8 @@ async function startBrowserAuth(authConfig, browser = 'system', logger) {
381
392
  }
382
393
  catch (error) {
383
394
  // If browser cannot be opened, show URL and throw error for consumer to catch
384
- log.error(`❌ Failed to open browser: ${error?.message || String(error)}. Please open manually: ${authorizationUrl}`);
385
- log.browserUrl(authorizationUrl);
395
+ log?.error(`❌ Failed to open browser: ${error?.message || String(error)}. Please open manually: ${authorizationUrl}`, { error: error?.message || String(error), url: authorizationUrl });
396
+ log?.info(`🔗 Open in browser: ${authorizationUrl}`, { url: authorizationUrl });
386
397
  // Throw error so consumer can distinguish this from "service key missing" error
387
398
  reject(new Error(`Browser opening failed for destination authentication. Please open manually: ${authorizationUrl}`));
388
399
  }
@@ -14,6 +14,7 @@ export interface ClientCredentialsResult {
14
14
  * @param clientId UAA client ID
15
15
  * @param clientSecret UAA client secret
16
16
  * @returns Promise that resolves to access token
17
+ * @internal - Internal function, not exported from package
17
18
  */
18
19
  export declare function getTokenWithClientCredentials(uaaUrl: string, clientId: string, clientSecret: string): Promise<ClientCredentialsResult>;
19
20
  //# sourceMappingURL=clientCredentialsAuth.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"clientCredentialsAuth.d.ts","sourceRoot":"","sources":["../../src/auth/clientCredentialsAuth.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH,MAAM,WAAW,uBAAuB;IACtC,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;;;;;GAMG;AACH,wBAAsB,6BAA6B,CACjD,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,MAAM,EAChB,YAAY,EAAE,MAAM,GACnB,OAAO,CAAC,uBAAuB,CAAC,CAoClC"}
1
+ {"version":3,"file":"clientCredentialsAuth.d.ts","sourceRoot":"","sources":["../../src/auth/clientCredentialsAuth.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH,MAAM,WAAW,uBAAuB;IACtC,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;;;;;;GAOG;AACH,wBAAsB,6BAA6B,CACjD,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,MAAM,EAChB,YAAY,EAAE,MAAM,GACnB,OAAO,CAAC,uBAAuB,CAAC,CAoClC"}
@@ -17,6 +17,7 @@ const axios_1 = __importDefault(require("axios"));
17
17
  * @param clientId UAA client ID
18
18
  * @param clientSecret UAA client secret
19
19
  * @returns Promise that resolves to access token
20
+ * @internal - Internal function, not exported from package
20
21
  */
21
22
  async function getTokenWithClientCredentials(uaaUrl, clientId, clientSecret) {
22
23
  try {
@@ -12,6 +12,7 @@ export interface TokenRefreshResult {
12
12
  * @param clientId UAA client ID
13
13
  * @param clientSecret UAA client secret
14
14
  * @returns Promise that resolves to new tokens
15
+ * @internal - Internal function, not exported from package
15
16
  */
16
17
  export declare function refreshJwtToken(refreshToken: string, uaaUrl: string, clientId: string, clientSecret: string): Promise<TokenRefreshResult>;
17
18
  //# sourceMappingURL=tokenRefresher.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"tokenRefresher.d.ts","sourceRoot":"","sources":["../../src/auth/tokenRefresher.ts"],"names":[],"mappings":"AAAA;;GAEG;AAIH,MAAM,WAAW,kBAAkB;IACjC,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED;;;;;;;GAOG;AACH,wBAAsB,eAAe,CACnC,YAAY,EAAE,MAAM,EACpB,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,MAAM,EAChB,YAAY,EAAE,MAAM,GACnB,OAAO,CAAC,kBAAkB,CAAC,CAqC7B"}
1
+ {"version":3,"file":"tokenRefresher.d.ts","sourceRoot":"","sources":["../../src/auth/tokenRefresher.ts"],"names":[],"mappings":"AAAA;;GAEG;AAIH,MAAM,WAAW,kBAAkB;IACjC,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED;;;;;;;;GAQG;AACH,wBAAsB,eAAe,CACnC,YAAY,EAAE,MAAM,EACpB,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,MAAM,EAChB,YAAY,EAAE,MAAM,GACnB,OAAO,CAAC,kBAAkB,CAAC,CAqC7B"}
@@ -15,6 +15,7 @@ const axios_1 = __importDefault(require("axios"));
15
15
  * @param clientId UAA client ID
16
16
  * @param clientSecret UAA client secret
17
17
  * @returns Promise that resolves to new tokens
18
+ * @internal - Internal function, not exported from package
18
19
  */
19
20
  async function refreshJwtToken(refreshToken, uaaUrl, clientId, clientSecret) {
20
21
  try {
package/dist/index.d.ts CHANGED
@@ -6,9 +6,4 @@
6
6
  */
7
7
  export { XsuaaTokenProvider } from './providers/XsuaaTokenProvider';
8
8
  export { BtpTokenProvider } from './providers/BtpTokenProvider';
9
- export { startBrowserAuth } from './auth/browserAuth';
10
- export { getTokenWithClientCredentials } from './auth/clientCredentialsAuth';
11
- export { refreshJwtToken } from './auth/tokenRefresher';
12
- export type { ClientCredentialsResult } from './auth/clientCredentialsAuth';
13
- export type { TokenRefreshResult } from './auth/tokenRefresher';
14
9
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,EAAE,kBAAkB,EAAE,MAAM,gCAAgC,CAAC;AACpE,OAAO,EAAE,gBAAgB,EAAE,MAAM,8BAA8B,CAAC;AAGhE,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AACtD,OAAO,EAAE,6BAA6B,EAAE,MAAM,8BAA8B,CAAC;AAC7E,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAGxD,YAAY,EAAE,uBAAuB,EAAE,MAAM,8BAA8B,CAAC;AAC5E,YAAY,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,EAAE,kBAAkB,EAAE,MAAM,gCAAgC,CAAC;AACpE,OAAO,EAAE,gBAAgB,EAAE,MAAM,8BAA8B,CAAC"}
package/dist/index.js CHANGED
@@ -6,16 +6,9 @@
6
6
  * Provides XSUAA and BTP token providers
7
7
  */
8
8
  Object.defineProperty(exports, "__esModule", { value: true });
9
- exports.refreshJwtToken = exports.getTokenWithClientCredentials = exports.startBrowserAuth = exports.BtpTokenProvider = exports.XsuaaTokenProvider = void 0;
9
+ exports.BtpTokenProvider = exports.XsuaaTokenProvider = void 0;
10
10
  // Token providers
11
11
  var XsuaaTokenProvider_1 = require("./providers/XsuaaTokenProvider");
12
12
  Object.defineProperty(exports, "XsuaaTokenProvider", { enumerable: true, get: function () { return XsuaaTokenProvider_1.XsuaaTokenProvider; } });
13
13
  var BtpTokenProvider_1 = require("./providers/BtpTokenProvider");
14
14
  Object.defineProperty(exports, "BtpTokenProvider", { enumerable: true, get: function () { return BtpTokenProvider_1.BtpTokenProvider; } });
15
- // Auth functions (for advanced usage)
16
- var browserAuth_1 = require("./auth/browserAuth");
17
- Object.defineProperty(exports, "startBrowserAuth", { enumerable: true, get: function () { return browserAuth_1.startBrowserAuth; } });
18
- var clientCredentialsAuth_1 = require("./auth/clientCredentialsAuth");
19
- Object.defineProperty(exports, "getTokenWithClientCredentials", { enumerable: true, get: function () { return clientCredentialsAuth_1.getTokenWithClientCredentials; } });
20
- var tokenRefresher_1 = require("./auth/tokenRefresher");
21
- Object.defineProperty(exports, "refreshJwtToken", { enumerable: true, get: function () { return tokenRefresher_1.refreshJwtToken; } });
@@ -11,6 +11,17 @@ import type { ITokenProvider, ITokenProviderOptions, ITokenProviderResult, IAuth
11
11
  * Uses browser-based OAuth2 (if no refresh token) or refresh token flow.
12
12
  */
13
13
  export declare class BtpTokenProvider implements ITokenProvider {
14
+ private readonly browserAuthPort;
15
+ constructor(browserAuthPort?: number);
16
+ /**
17
+ * Private method wrapper for browser authentication
18
+ * Proxies port from constructor to internal function
19
+ */
20
+ private startBrowserAuth;
21
+ /**
22
+ * Private method wrapper for token refresh
23
+ */
24
+ private refreshJwtToken;
14
25
  getConnectionConfig(authConfig: IAuthorizationConfig, options?: ITokenProviderOptions): Promise<ITokenProviderResult>;
15
26
  validateToken(token: string, serviceUrl?: string): Promise<boolean>;
16
27
  }
@@ -1 +1 @@
1
- {"version":3,"file":"BtpTokenProvider.d.ts","sourceRoot":"","sources":["../../src/providers/BtpTokenProvider.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,qBAAqB,EAAE,oBAAoB,EAAE,oBAAoB,EAAE,MAAM,0BAA0B,CAAC;AAKlI;;;;GAIG;AACH,qBAAa,gBAAiB,YAAW,cAAc;IAC/C,mBAAmB,CACvB,UAAU,EAAE,oBAAoB,EAChC,OAAO,CAAC,EAAE,qBAAqB,GAC9B,OAAO,CAAC,oBAAoB,CAAC;IAmC1B,aAAa,CAAC,KAAK,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;CA0C1E"}
1
+ {"version":3,"file":"BtpTokenProvider.d.ts","sourceRoot":"","sources":["../../src/providers/BtpTokenProvider.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,qBAAqB,EAAE,oBAAoB,EAAE,oBAAoB,EAAW,MAAM,0BAA0B,CAAC;AAO3I;;;;GAIG;AACH,qBAAa,gBAAiB,YAAW,cAAc;IACrD,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAS;gBAE7B,eAAe,CAAC,EAAE,MAAM;IAKpC;;;OAGG;YACW,gBAAgB;IAQ9B;;OAEG;YACW,eAAe;IASvB,mBAAmB,CACvB,UAAU,EAAE,oBAAoB,EAChC,OAAO,CAAC,EAAE,qBAAqB,GAC9B,OAAO,CAAC,oBAAoB,CAAC;IAmC1B,aAAa,CAAC,KAAK,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;CA0C1E"}
@@ -10,15 +10,34 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
10
10
  };
11
11
  Object.defineProperty(exports, "__esModule", { value: true });
12
12
  exports.BtpTokenProvider = void 0;
13
+ const axios_1 = __importDefault(require("axios"));
14
+ // Import internal functions (not exported)
13
15
  const browserAuth_1 = require("../auth/browserAuth");
14
16
  const tokenRefresher_1 = require("../auth/tokenRefresher");
15
- const axios_1 = __importDefault(require("axios"));
16
17
  /**
17
18
  * BTP/ABAP token provider implementation
18
19
  *
19
20
  * Uses browser-based OAuth2 (if no refresh token) or refresh token flow.
20
21
  */
21
22
  class BtpTokenProvider {
23
+ browserAuthPort;
24
+ constructor(browserAuthPort) {
25
+ // Default to 3001 if not specified
26
+ this.browserAuthPort = browserAuthPort ?? 3001;
27
+ }
28
+ /**
29
+ * Private method wrapper for browser authentication
30
+ * Proxies port from constructor to internal function
31
+ */
32
+ async startBrowserAuth(authConfig, browser, logger) {
33
+ return (0, browserAuth_1.startBrowserAuth)(authConfig, browser, logger, this.browserAuthPort);
34
+ }
35
+ /**
36
+ * Private method wrapper for token refresh
37
+ */
38
+ async refreshJwtToken(refreshToken, uaaUrl, clientId, clientSecret) {
39
+ return (0, tokenRefresher_1.refreshJwtToken)(refreshToken, uaaUrl, clientId, clientSecret);
40
+ }
22
41
  async getConnectionConfig(authConfig, options) {
23
42
  const logger = options?.logger;
24
43
  const browser = options?.browser || 'system';
@@ -28,14 +47,14 @@ class BtpTokenProvider {
28
47
  if (logger) {
29
48
  logger.debug('No refresh token found. Starting browser authentication...');
30
49
  }
31
- result = await (0, browserAuth_1.startBrowserAuth)(authConfig, browser, logger);
50
+ result = await this.startBrowserAuth(authConfig, browser, logger);
32
51
  }
33
52
  else {
34
53
  // Use refresh token to get new access token
35
54
  if (logger) {
36
55
  logger.debug('Refreshing token using refresh token...');
37
56
  }
38
- result = await (0, tokenRefresher_1.refreshJwtToken)(authConfig.refreshToken, authConfig.uaaUrl, authConfig.uaaClientId, authConfig.uaaClientSecret);
57
+ result = await this.refreshJwtToken(authConfig.refreshToken, authConfig.uaaUrl, authConfig.uaaClientId, authConfig.uaaClientSecret);
39
58
  }
40
59
  return {
41
60
  connectionConfig: {
@@ -11,6 +11,10 @@ import type { ITokenProvider, ITokenProviderOptions, ITokenProviderResult, IAuth
11
11
  * Uses client_credentials grant type - no browser, no refresh token needed.
12
12
  */
13
13
  export declare class XsuaaTokenProvider implements ITokenProvider {
14
+ /**
15
+ * Private method wrapper for client credentials authentication
16
+ */
17
+ private getTokenWithClientCredentials;
14
18
  getConnectionConfig(authConfig: IAuthorizationConfig, options?: ITokenProviderOptions): Promise<ITokenProviderResult>;
15
19
  validateToken(token: string, serviceUrl?: string): Promise<boolean>;
16
20
  }
@@ -1 +1 @@
1
- {"version":3,"file":"XsuaaTokenProvider.d.ts","sourceRoot":"","sources":["../../src/providers/XsuaaTokenProvider.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,qBAAqB,EAAE,oBAAoB,EAAE,oBAAoB,EAAE,MAAM,0BAA0B,CAAC;AAIlI;;;;GAIG;AACH,qBAAa,kBAAmB,YAAW,cAAc;IACjD,mBAAmB,CACvB,UAAU,EAAE,oBAAoB,EAChC,OAAO,CAAC,EAAE,qBAAqB,GAC9B,OAAO,CAAC,oBAAoB,CAAC;IAyB1B,aAAa,CAAC,KAAK,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;CAgD1E"}
1
+ {"version":3,"file":"XsuaaTokenProvider.d.ts","sourceRoot":"","sources":["../../src/providers/XsuaaTokenProvider.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,qBAAqB,EAAE,oBAAoB,EAAE,oBAAoB,EAAE,MAAM,0BAA0B,CAAC;AAMlI;;;;GAIG;AACH,qBAAa,kBAAmB,YAAW,cAAc;IACvD;;OAEG;YACW,6BAA6B;IAQrC,mBAAmB,CACvB,UAAU,EAAE,oBAAoB,EAChC,OAAO,CAAC,EAAE,qBAAqB,GAC9B,OAAO,CAAC,oBAAoB,CAAC;IAyB1B,aAAa,CAAC,KAAK,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;CAgD1E"}
@@ -10,21 +10,28 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
10
10
  };
11
11
  Object.defineProperty(exports, "__esModule", { value: true });
12
12
  exports.XsuaaTokenProvider = void 0;
13
- const clientCredentialsAuth_1 = require("../auth/clientCredentialsAuth");
14
13
  const axios_1 = __importDefault(require("axios"));
14
+ // Import internal function (not exported)
15
+ const clientCredentialsAuth_1 = require("../auth/clientCredentialsAuth");
15
16
  /**
16
17
  * XSUAA token provider implementation
17
18
  *
18
19
  * Uses client_credentials grant type - no browser, no refresh token needed.
19
20
  */
20
21
  class XsuaaTokenProvider {
22
+ /**
23
+ * Private method wrapper for client credentials authentication
24
+ */
25
+ async getTokenWithClientCredentials(uaaUrl, clientId, clientSecret) {
26
+ return (0, clientCredentialsAuth_1.getTokenWithClientCredentials)(uaaUrl, clientId, clientSecret);
27
+ }
21
28
  async getConnectionConfig(authConfig, options) {
22
29
  const logger = options?.logger;
23
30
  if (logger) {
24
31
  logger.debug('Using client_credentials grant type for XSUAA...');
25
32
  }
26
33
  // XSUAA uses client_credentials - no refresh token needed
27
- const result = await (0, clientCredentialsAuth_1.getTokenWithClientCredentials)(authConfig.uaaUrl, authConfig.uaaClientId, authConfig.uaaClientSecret);
34
+ const result = await this.getTokenWithClientCredentials(authConfig.uaaUrl, authConfig.uaaClientId, authConfig.uaaClientSecret);
28
35
  // XSUAA doesn't provide serviceUrl in authorization config
29
36
  // It's provided separately (from YAML, parameter, or request header)
30
37
  return {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mcp-abap-adt/auth-providers",
3
- "version": "0.1.2",
3
+ "version": "0.1.4",
4
4
  "description": "Token providers for MCP ABAP ADT auth-broker - XSUAA and BTP token providers",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",