@mcp-abap-adt/auth-broker 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (50) hide show
  1. package/CHANGELOG.md +94 -0
  2. package/CONTRIBUTORS.md +33 -0
  3. package/LICENSE +22 -0
  4. package/README.md +166 -0
  5. package/dist/AuthBroker.d.ts +62 -0
  6. package/dist/AuthBroker.d.ts.map +1 -0
  7. package/dist/AuthBroker.js +219 -0
  8. package/dist/__tests__/testHelpers.d.ts +44 -0
  9. package/dist/__tests__/testHelpers.d.ts.map +1 -0
  10. package/dist/__tests__/testHelpers.js +129 -0
  11. package/dist/browserAuth.d.ts +17 -0
  12. package/dist/browserAuth.d.ts.map +1 -0
  13. package/dist/browserAuth.js +301 -0
  14. package/dist/cache.d.ts +20 -0
  15. package/dist/cache.d.ts.map +1 -0
  16. package/dist/cache.js +46 -0
  17. package/dist/envLoader.d.ts +12 -0
  18. package/dist/envLoader.d.ts.map +1 -0
  19. package/dist/envLoader.js +90 -0
  20. package/dist/getToken.d.ts +14 -0
  21. package/dist/getToken.d.ts.map +1 -0
  22. package/dist/getToken.js +62 -0
  23. package/dist/index.d.ts +8 -0
  24. package/dist/index.d.ts.map +1 -0
  25. package/dist/index.js +12 -0
  26. package/dist/logger.d.ts +29 -0
  27. package/dist/logger.d.ts.map +1 -0
  28. package/dist/logger.js +131 -0
  29. package/dist/pathResolver.d.ts +21 -0
  30. package/dist/pathResolver.d.ts.map +1 -0
  31. package/dist/pathResolver.js +105 -0
  32. package/dist/refreshToken.d.ts +14 -0
  33. package/dist/refreshToken.d.ts.map +1 -0
  34. package/dist/refreshToken.js +71 -0
  35. package/dist/serviceKeyLoader.d.ts +12 -0
  36. package/dist/serviceKeyLoader.d.ts.map +1 -0
  37. package/dist/serviceKeyLoader.js +72 -0
  38. package/dist/tokenRefresher.d.ts +17 -0
  39. package/dist/tokenRefresher.d.ts.map +1 -0
  40. package/dist/tokenRefresher.js +53 -0
  41. package/dist/tokenStorage.d.ts +15 -0
  42. package/dist/tokenStorage.d.ts.map +1 -0
  43. package/dist/tokenStorage.js +107 -0
  44. package/dist/tokenValidator.d.ts +11 -0
  45. package/dist/tokenValidator.d.ts.map +1 -0
  46. package/dist/tokenValidator.js +108 -0
  47. package/dist/types.d.ts +37 -0
  48. package/dist/types.d.ts.map +1 -0
  49. package/dist/types.js +5 -0
  50. package/package.json +64 -0
package/CHANGELOG.md ADDED
@@ -0,0 +1,94 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project will be documented in this file.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
+
8
+ ## Contributors
9
+
10
+ Thank you to all contributors! See [CONTRIBUTORS.md](CONTRIBUTORS.md) for the complete list.
11
+
12
+ ## [0.1.0] - 2025-01-XX
13
+
14
+ ### Added
15
+ - **AuthBroker class** - Main class for managing JWT authentication tokens
16
+ - `getToken(destination)` - Get token for destination (loads, validates, refreshes if needed)
17
+ - `refreshToken(destination)` - Force refresh token using service key or browser authentication
18
+ - `clearCache(destination)` - Clear cached token for specific destination
19
+ - `clearAllCache()` - Clear all cached tokens
20
+ - **Multi-path file search** - Configurable search paths for `.env` and `.json` files
21
+ - Constructor parameter (highest priority)
22
+ - `AUTH_BROKER_PATH` environment variable
23
+ - Current working directory (fallback)
24
+ - **Token management**
25
+ - Automatic token validation before use
26
+ - Automatic token refresh when expired
27
+ - In-memory token caching for performance
28
+ - Token expiry information in `.env` file comments
29
+ - **Browser-based OAuth2 authentication**
30
+ - Automatic browser opening for initial authentication
31
+ - Configurable browser selection (chrome, edge, firefox, system, none)
32
+ - Manual URL copy option when browser cannot be opened
33
+ - OAuth2 callback server with success page
34
+ - **Service key support**
35
+ - Load service keys from `{destination}.json` files
36
+ - Support for multiple service key formats (url, abap.url, sap_url)
37
+ - Extract UAA credentials for token refresh
38
+ - **Environment file management**
39
+ - Load tokens from `{destination}.env` files
40
+ - Automatic `.env` file creation after authentication
41
+ - Atomic file writes for safe updates
42
+ - Format compatible with `sap-abap-auth` utility
43
+ - **Comprehensive error handling**
44
+ - Clear error messages with file location instructions
45
+ - Searched paths listed in error messages
46
+ - Graceful handling of missing files and invalid configurations
47
+ - **TypeScript support**
48
+ - Full TypeScript definitions
49
+ - Type-safe API
50
+ - Exported types: `EnvConfig`, `ServiceKey`
51
+ - **Configurable logging system**
52
+ - Injectable logger interface for custom logging implementations
53
+ - Environment variable `DEBUG_AUTH_LOG` to control debug output
54
+ - Minimal logging by default (only errors and manual URLs)
55
+ - Detailed debug logging when `DEBUG_AUTH_LOG=true`
56
+ - Custom logger support via constructor injection
57
+ - **Testing infrastructure**
58
+ - Unit tests for all components
59
+ - Integration tests for authentication flows
60
+ - Sequential test execution for reliable results
61
+ - Test scenarios covering error cases, browser auth, and token refresh
62
+ - Silent test output (no verbose logging during test execution)
63
+ - Clean test output focusing on failures
64
+ - **Documentation**
65
+ - Complete API documentation
66
+ - Architecture documentation
67
+ - Installation guide
68
+ - Usage guide with examples
69
+ - Testing methodology guide
70
+ - Logging configuration guide
71
+
72
+ ### Changed
73
+ - **Logging behavior**
74
+ - Default logger now shows minimal output (only errors and manual URLs)
75
+ - Debug messages only visible when `DEBUG_AUTH_LOG=true`
76
+ - Browser opening notifications moved to debug level
77
+ - Token refresh operations logged at debug level
78
+ - **Test output**
79
+ - Removed verbose logging from test files
80
+ - Tests now produce clean, focused output
81
+ - Only test results and errors are displayed
82
+ - Improved readability and CI/CD integration
83
+
84
+ ### Technical Details
85
+ - **Dependencies**
86
+ - `@mcp-abap-adt/connection` - Token refresh utilities
87
+ - `axios` - HTTP requests
88
+ - `express` - OAuth callback server
89
+ - `open` - Browser opening utility
90
+ - **Node.js version**: >= 18.0.0
91
+ - **Module system**: CommonJS
92
+ - **Build output**: TypeScript compiled to JavaScript with type definitions
93
+ - **Logging**: Injectable logger interface with environment variable control
94
+
@@ -0,0 +1,33 @@
1
+ # Contributors
2
+
3
+ Thank you to all contributors who have helped make `@mcp-abap-adt/auth-broker` better!
4
+
5
+ ## How to Contribute
6
+
7
+ We welcome contributions! Please see the project documentation for details on how to get started.
8
+
9
+ ## Contributors
10
+
11
+ <!-- Contributors are listed alphabetically by last name -->
12
+
13
+ ### Core Contributors
14
+
15
+ - **Oleksii Kyslytsia** - Project creator and maintainer
16
+
17
+ ---
18
+
19
+ ## Recognition
20
+
21
+ We appreciate every contribution, whether it's:
22
+ - 🐛 Bug reports and fixes
23
+ - ✨ New features and enhancements
24
+ - 📚 Documentation improvements
25
+ - 🧪 Test coverage
26
+ - 💬 Feedback and suggestions
27
+
28
+ Every contribution helps make `@mcp-abap-adt/auth-broker` better for everyone!
29
+
30
+ ---
31
+
32
+ **Note:** This list is manually maintained. If you've contributed but don't see your name here, please open an issue or submit a PR to update this file.
33
+
package/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Oleksii Kyslytsia
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
22
+
package/README.md ADDED
@@ -0,0 +1,166 @@
1
+ # @mcp-abap-adt/auth-broker
2
+
3
+ JWT authentication broker for MCP ABAP ADT server. Manages authentication tokens based on destination headers, automatically loading tokens from `.env` files and refreshing them using service keys when needed.
4
+
5
+ ## Features
6
+
7
+ - 🔐 **Destination-based Authentication**: Load tokens based on `x-mcp-destination` header
8
+ - 📁 **Environment File Support**: Automatically loads tokens from `{destination}.env` files
9
+ - 🔄 **Automatic Token Refresh**: Refreshes expired tokens using service keys from `{destination}.json` files
10
+ - ✅ **Token Validation**: Validates tokens by testing connection to SAP system
11
+ - 💾 **Token Caching**: In-memory caching for improved performance
12
+ - 🔧 **Configurable Base Path**: Customize where `.env` and `.json` files are stored
13
+
14
+ ## Installation
15
+
16
+ ```bash
17
+ npm install @mcp-abap-adt/auth-broker
18
+ ```
19
+
20
+ ## Usage
21
+
22
+ ```typescript
23
+ import { AuthBroker } from '@mcp-abap-adt/auth-broker';
24
+
25
+ const broker = new AuthBroker('/path/to/destinations', 'chrome');
26
+
27
+ // Get token for destination (loads from .env, validates, refreshes if needed)
28
+ const token = await broker.getToken('TRIAL');
29
+
30
+ // Force refresh token using service key
31
+ const newToken = await broker.refreshToken('TRIAL');
32
+ ```
33
+
34
+ ## Configuration
35
+
36
+ ### Environment Variables
37
+
38
+ - `AUTH_BROKER_PATH` - Colon/semicolon-separated paths for searching `.env` and `.json` files (default: current working directory)
39
+ - `DEBUG_AUTH_LOG` - Set to `true` to enable debug logging (default: `false`)
40
+
41
+ ### File Structure
42
+
43
+ #### Environment File (`{destination}.env`)
44
+
45
+ ```env
46
+ SAP_URL=https://your-system.abap.us10.hana.ondemand.com
47
+ SAP_CLIENT=100
48
+ SAP_JWT_TOKEN=eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...
49
+ SAP_REFRESH_TOKEN=refresh_token_string
50
+ SAP_UAA_URL=https://your-account.authentication.us10.hana.ondemand.com
51
+ SAP_UAA_CLIENT_ID=client_id
52
+ SAP_UAA_CLIENT_SECRET=client_secret
53
+ ```
54
+
55
+ #### Service Key File (`{destination}.json`)
56
+
57
+ ```json
58
+ {
59
+ "url": "https://your-system.abap.us10.hana.ondemand.com",
60
+ "uaa": {
61
+ "url": "https://your-account.authentication.us10.hana.ondemand.com",
62
+ "clientid": "your_client_id",
63
+ "clientsecret": "your_client_secret"
64
+ }
65
+ }
66
+ ```
67
+
68
+ ## API
69
+
70
+ ### `AuthBroker`
71
+
72
+ #### Constructor
73
+
74
+ ```typescript
75
+ new AuthBroker(searchPaths?: string | string[], browser?: string)
76
+ ```
77
+
78
+ - `searchPaths` - Optional base directory or array of directories for searching `.env` and `.json` files
79
+ - `browser` - Optional browser name for authentication (`chrome`, `edge`, `firefox`, `system`, `none`). Default: `system`
80
+
81
+ #### Methods
82
+
83
+ ##### `getToken(destination: string): Promise<string>`
84
+
85
+ Gets authentication token for destination. Tries to load from `.env` file, validates it, and refreshes if needed.
86
+
87
+ ##### `refreshToken(destination: string): Promise<string>`
88
+
89
+ Force refresh token for destination using service key from `{destination}.json` file.
90
+
91
+ ##### `clearCache(destination: string): void`
92
+
93
+ Clear cached token for specific destination.
94
+
95
+ ##### `clearAllCache(): void`
96
+
97
+ Clear all cached tokens.
98
+
99
+ ## Testing
100
+
101
+ Tests are located in `src/__tests__/` and use Jest as the test runner.
102
+
103
+ ### Running Tests
104
+
105
+ ```bash
106
+ # Run all tests
107
+ npm test
108
+
109
+ # Run specific test file (all tests in that file)
110
+ npm test -- getToken.test.ts
111
+ npm test -- refreshToken.test.ts
112
+
113
+ # Run specific test by name/pattern
114
+ npm test -- getToken.test.ts -t "Test 1"
115
+ npm test -- getToken.test.ts -t "Test 2"
116
+ npm test -- getToken.test.ts -t "Test 3"
117
+
118
+ # Run test group (e.g., all getToken tests)
119
+ npm test -- getToken.test.ts
120
+
121
+ # Note: Test 2 requires Test 1 to pass first (test1Passed flag)
122
+ # To run Test 2 alone, you may need to run all tests in the file:
123
+ npm test -- getToken.test.ts
124
+ ```
125
+
126
+ ### Test Structure
127
+
128
+ Tests are designed to run sequentially (guaranteed by `maxWorkers: 1` and `maxConcurrency: 1` in `jest.config.js`):
129
+
130
+ 1. **Test 1**: Verifies error handling for non-existent destination (`NO_EXISTS`)
131
+ - Requires: `NO_EXISTS.json` should NOT exist
132
+
133
+ 2. **Test 2**: Tests browser authentication when service key exists but `.env` file doesn't
134
+ - Requires: `TRIAL.json` must exist, `TRIAL.env` should NOT exist
135
+ - Will open browser for OAuth authentication
136
+
137
+ 3. **Test 3**: Tests token refresh using existing `.env` file
138
+ - Requires: `TRIAL.json` and `TRIAL.env` must exist
139
+ - Can run independently if `.env` file exists (created manually or by Test 2)
140
+
141
+ ### Test Setup
142
+
143
+ Place your service key file in `./test-destinations/TRIAL.json` to run tests 2 and 3.
144
+
145
+ Tests will automatically skip if required files are missing or present when they shouldn't be.
146
+
147
+ ## Documentation
148
+
149
+ Complete documentation is available in the [`docs/`](docs/) directory:
150
+
151
+ - **[Architecture](docs/architecture/ARCHITECTURE.md)** - System architecture and design decisions
152
+ - **[Development](docs/development/)** - Testing methodology and development roadmap
153
+ - **[Development Roadmap](docs/development/DEVELOPMENT_ROADMAP.md)** - Development roadmap and future plans
154
+ - **[Installation](docs/installing/INSTALLATION.md)** - Installation and setup guide
155
+ - **[Usage](docs/using/USAGE.md)** - API reference and usage examples
156
+
157
+ See [docs/README.md](docs/README.md) for the complete documentation index.
158
+
159
+ ## Contributors
160
+
161
+ Thank you to all contributors! See [CONTRIBUTORS.md](CONTRIBUTORS.md) for the complete list.
162
+
163
+ ## License
164
+
165
+ MIT
166
+
@@ -0,0 +1,62 @@
1
+ /**
2
+ * Main AuthBroker class for managing JWT tokens based on destinations
3
+ */
4
+ import { Logger } from './logger';
5
+ /**
6
+ * AuthBroker manages JWT authentication tokens for destinations
7
+ */
8
+ export declare class AuthBroker {
9
+ private searchPaths;
10
+ private browser;
11
+ private logger;
12
+ /**
13
+ * Create a new AuthBroker instance
14
+ * @param searchPaths Optional search paths for .env and .json files.
15
+ * Can be a single path (string) or array of paths.
16
+ * Priority:
17
+ * 1. Constructor parameter (highest)
18
+ * 2. AUTH_BROKER_PATH environment variable (colon/semicolon-separated)
19
+ * 3. Current working directory (lowest)
20
+ * @param browser Optional browser name for authentication (chrome, edge, firefox, system, none).
21
+ * Default: 'system' (system default browser).
22
+ * Use 'none' to print URL instead of opening browser.
23
+ * @param logger Optional logger instance. If not provided, uses default logger.
24
+ */
25
+ constructor(searchPaths?: string | string[], browser?: string, logger?: Logger);
26
+ /**
27
+ * Get authentication token for destination.
28
+ * Tries to load from .env file, validates it, and refreshes if needed.
29
+ * @param destination Destination name (e.g., "TRIAL")
30
+ * @returns Promise that resolves to JWT token string
31
+ * @throws Error if neither .env file nor service key found
32
+ */
33
+ getToken(destination: string): Promise<string>;
34
+ /**
35
+ * Force refresh token for destination using service key.
36
+ * If no refresh token exists, starts browser authentication flow.
37
+ * @param destination Destination name (e.g., "TRIAL")
38
+ * @returns Promise that resolves to new JWT token string
39
+ */
40
+ refreshToken(destination: string): Promise<string>;
41
+ /**
42
+ * Save token to {destination}.env file
43
+ * Creates .env file similar to sap-abap-auth utility format
44
+ * @private
45
+ */
46
+ private saveTokenToEnv;
47
+ /**
48
+ * Get token expiry information from JWT token
49
+ * @private
50
+ */
51
+ private getTokenExpiry;
52
+ /**
53
+ * Clear cached token for specific destination
54
+ * @param destination Destination name
55
+ */
56
+ clearCache(destination: string): void;
57
+ /**
58
+ * Clear all cached tokens
59
+ */
60
+ clearAllCache(): void;
61
+ }
62
+ //# sourceMappingURL=AuthBroker.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AuthBroker.d.ts","sourceRoot":"","sources":["../src/AuthBroker.ts"],"names":[],"mappings":"AAAA;;GAEG;AAYH,OAAO,EAAE,MAAM,EAAiB,MAAM,UAAU,CAAC;AAIjD;;GAEG;AACH,qBAAa,UAAU;IACrB,OAAO,CAAC,WAAW,CAAW;IAC9B,OAAO,CAAC,OAAO,CAAqB;IACpC,OAAO,CAAC,MAAM,CAAS;IAEvB;;;;;;;;;;;;OAYG;gBACS,WAAW,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,EAAE,OAAO,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM;IAM9E;;;;;;OAMG;IACG,QAAQ,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAKpD;;;;;OAKG;IACG,YAAY,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAKxD;;;;OAIG;YACW,cAAc;IA6E5B;;;OAGG;IACH,OAAO,CAAC,cAAc;IAyCtB;;;OAGG;IACH,UAAU,CAAC,WAAW,EAAE,MAAM,GAAG,IAAI;IAIrC;;OAEG;IACH,aAAa,IAAI,IAAI;CAGtB"}
@@ -0,0 +1,219 @@
1
+ "use strict";
2
+ /**
3
+ * Main AuthBroker class for managing JWT tokens based on destinations
4
+ */
5
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
6
+ if (k2 === undefined) k2 = k;
7
+ var desc = Object.getOwnPropertyDescriptor(m, k);
8
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
9
+ desc = { enumerable: true, get: function() { return m[k]; } };
10
+ }
11
+ Object.defineProperty(o, k2, desc);
12
+ }) : (function(o, m, k, k2) {
13
+ if (k2 === undefined) k2 = k;
14
+ o[k2] = m[k];
15
+ }));
16
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
17
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
18
+ }) : function(o, v) {
19
+ o["default"] = v;
20
+ });
21
+ var __importStar = (this && this.__importStar) || (function () {
22
+ var ownKeys = function(o) {
23
+ ownKeys = Object.getOwnPropertyNames || function (o) {
24
+ var ar = [];
25
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
26
+ return ar;
27
+ };
28
+ return ownKeys(o);
29
+ };
30
+ return function (mod) {
31
+ if (mod && mod.__esModule) return mod;
32
+ var result = {};
33
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
34
+ __setModuleDefault(result, mod);
35
+ return result;
36
+ };
37
+ })();
38
+ Object.defineProperty(exports, "__esModule", { value: true });
39
+ exports.AuthBroker = void 0;
40
+ const fs = __importStar(require("fs"));
41
+ const path = __importStar(require("path"));
42
+ const cache_1 = require("./cache");
43
+ const pathResolver_1 = require("./pathResolver");
44
+ const logger_1 = require("./logger");
45
+ const refreshToken_1 = require("./refreshToken");
46
+ const getToken_1 = require("./getToken");
47
+ /**
48
+ * AuthBroker manages JWT authentication tokens for destinations
49
+ */
50
+ class AuthBroker {
51
+ searchPaths;
52
+ browser;
53
+ logger;
54
+ /**
55
+ * Create a new AuthBroker instance
56
+ * @param searchPaths Optional search paths for .env and .json files.
57
+ * Can be a single path (string) or array of paths.
58
+ * Priority:
59
+ * 1. Constructor parameter (highest)
60
+ * 2. AUTH_BROKER_PATH environment variable (colon/semicolon-separated)
61
+ * 3. Current working directory (lowest)
62
+ * @param browser Optional browser name for authentication (chrome, edge, firefox, system, none).
63
+ * Default: 'system' (system default browser).
64
+ * Use 'none' to print URL instead of opening browser.
65
+ * @param logger Optional logger instance. If not provided, uses default logger.
66
+ */
67
+ constructor(searchPaths, browser, logger) {
68
+ this.searchPaths = (0, pathResolver_1.resolveSearchPaths)(searchPaths);
69
+ this.browser = browser || 'system';
70
+ this.logger = logger || logger_1.defaultLogger;
71
+ }
72
+ /**
73
+ * Get authentication token for destination.
74
+ * Tries to load from .env file, validates it, and refreshes if needed.
75
+ * @param destination Destination name (e.g., "TRIAL")
76
+ * @returns Promise that resolves to JWT token string
77
+ * @throws Error if neither .env file nor service key found
78
+ */
79
+ async getToken(destination) {
80
+ // Use getToken function with logger
81
+ return (0, getToken_1.getToken)(destination, this.searchPaths, this.logger);
82
+ }
83
+ /**
84
+ * Force refresh token for destination using service key.
85
+ * If no refresh token exists, starts browser authentication flow.
86
+ * @param destination Destination name (e.g., "TRIAL")
87
+ * @returns Promise that resolves to new JWT token string
88
+ */
89
+ async refreshToken(destination) {
90
+ // Use refreshToken function with logger and browser
91
+ return (0, refreshToken_1.refreshToken)(destination, this.searchPaths, this.logger);
92
+ }
93
+ /**
94
+ * Save token to {destination}.env file
95
+ * Creates .env file similar to sap-abap-auth utility format
96
+ * @private
97
+ */
98
+ async saveTokenToEnv(destination, savePath, config) {
99
+ // Ensure directory exists
100
+ if (!fs.existsSync(savePath)) {
101
+ fs.mkdirSync(savePath, { recursive: true });
102
+ }
103
+ const envFilePath = path.join(savePath, `${destination}.env`);
104
+ const tempFilePath = `${envFilePath}.tmp`;
105
+ // Write to temporary file first (atomic write)
106
+ // Format similar to sap-abap-auth utility - always create fresh file
107
+ const envLines = [];
108
+ // Add token expiry information if we can decode JWT
109
+ const jwtExpiry = this.getTokenExpiry(config.jwtToken);
110
+ const refreshExpiry = config.refreshToken ? this.getTokenExpiry(config.refreshToken) : null;
111
+ if (jwtExpiry || refreshExpiry) {
112
+ envLines.push('# Token Expiry Information (auto-generated)');
113
+ if (jwtExpiry) {
114
+ envLines.push(`# JWT Token expires: ${jwtExpiry.readableDate} (UTC)`);
115
+ envLines.push(`# JWT Token expires at: ${jwtExpiry.dateString}`);
116
+ }
117
+ else {
118
+ envLines.push('# JWT Token expiry: Unable to determine (token may not be a standard JWT)');
119
+ }
120
+ if (refreshExpiry) {
121
+ envLines.push(`# Refresh Token expires: ${refreshExpiry.readableDate} (UTC)`);
122
+ envLines.push(`# Refresh Token expires at: ${refreshExpiry.dateString}`);
123
+ }
124
+ else if (config.refreshToken) {
125
+ envLines.push('# Refresh Token expiry: Unable to determine (token may not be a standard JWT)');
126
+ }
127
+ envLines.push('');
128
+ }
129
+ // Write JWT auth parameters (similar to sap-abap-auth format)
130
+ // Required fields
131
+ envLines.push(`SAP_URL=${config.sapUrl}`);
132
+ if (config.sapClient) {
133
+ envLines.push(`SAP_CLIENT=${config.sapClient}`);
134
+ }
135
+ if (config.language) {
136
+ envLines.push(`SAP_LANGUAGE=${config.language}`);
137
+ }
138
+ envLines.push('TLS_REJECT_UNAUTHORIZED=0');
139
+ envLines.push('SAP_AUTH_TYPE=jwt');
140
+ envLines.push(`SAP_JWT_TOKEN=${config.jwtToken}`);
141
+ if (config.refreshToken) {
142
+ envLines.push(`SAP_REFRESH_TOKEN=${config.refreshToken}`);
143
+ }
144
+ if (config.uaaUrl) {
145
+ envLines.push(`SAP_UAA_URL=${config.uaaUrl}`);
146
+ }
147
+ if (config.uaaClientId) {
148
+ envLines.push(`SAP_UAA_CLIENT_ID=${config.uaaClientId}`);
149
+ }
150
+ if (config.uaaClientSecret) {
151
+ envLines.push(`SAP_UAA_CLIENT_SECRET=${config.uaaClientSecret}`);
152
+ }
153
+ envLines.push('');
154
+ envLines.push('# For JWT authentication');
155
+ envLines.push('# SAP_USERNAME=your_username');
156
+ envLines.push('# SAP_PASSWORD=your_password');
157
+ const envContent = envLines.join('\n') + '\n';
158
+ // Write to temp file
159
+ fs.writeFileSync(tempFilePath, envContent, 'utf8');
160
+ // Atomic rename
161
+ fs.renameSync(tempFilePath, envFilePath);
162
+ }
163
+ /**
164
+ * Get token expiry information from JWT token
165
+ * @private
166
+ */
167
+ getTokenExpiry(token) {
168
+ try {
169
+ // JWT tokens have format: header.payload.signature
170
+ const parts = token.split('.');
171
+ if (parts.length !== 3) {
172
+ return null;
173
+ }
174
+ // Decode payload (base64url)
175
+ const payload = parts[1];
176
+ // Add padding if needed
177
+ const padded = payload + '='.repeat((4 - payload.length % 4) % 4);
178
+ const decoded = Buffer.from(padded.replace(/-/g, '+').replace(/_/g, '/'), 'base64').toString('utf8');
179
+ const parsed = JSON.parse(decoded);
180
+ // Check for exp claim
181
+ if (parsed.exp) {
182
+ const expiryDate = new Date(parsed.exp * 1000);
183
+ const readableDate = expiryDate.toLocaleString('en-US', {
184
+ weekday: 'long',
185
+ year: 'numeric',
186
+ month: 'long',
187
+ day: 'numeric',
188
+ hour: '2-digit',
189
+ minute: '2-digit',
190
+ second: '2-digit',
191
+ timeZone: 'UTC',
192
+ timeZoneName: 'short',
193
+ });
194
+ return {
195
+ dateString: expiryDate.toISOString(),
196
+ readableDate: readableDate,
197
+ };
198
+ }
199
+ return null;
200
+ }
201
+ catch {
202
+ return null;
203
+ }
204
+ }
205
+ /**
206
+ * Clear cached token for specific destination
207
+ * @param destination Destination name
208
+ */
209
+ clearCache(destination) {
210
+ (0, cache_1.clearCache)(destination);
211
+ }
212
+ /**
213
+ * Clear all cached tokens
214
+ */
215
+ clearAllCache() {
216
+ (0, cache_1.clearAllCache)();
217
+ }
218
+ }
219
+ exports.AuthBroker = AuthBroker;
@@ -0,0 +1,44 @@
1
+ /**
2
+ * Common test helpers for AuthBroker tests
3
+ */
4
+ import { AuthBroker } from '../AuthBroker';
5
+ export declare const TEST_DESTINATIONS_PATH: string;
6
+ export interface TestBrokers {
7
+ tempDir: string;
8
+ broker: AuthBroker;
9
+ testDestinationsBroker: AuthBroker;
10
+ }
11
+ /**
12
+ * Setup test brokers for a test suite
13
+ */
14
+ export declare function setupTestBrokers(testName: string): TestBrokers;
15
+ /**
16
+ * Cleanup test brokers
17
+ */
18
+ export declare function cleanupTestBrokers(brokers: TestBrokers): void;
19
+ /**
20
+ * Check if NO_EXISTS.json exists and skip test if it does
21
+ */
22
+ export declare function checkNoExistsFile(): boolean;
23
+ /**
24
+ * Prepare Test 2: Remove TRIAL.env if exists, check for TRIAL.json
25
+ */
26
+ export declare function prepareTest2(): {
27
+ envFile: string;
28
+ serviceKeyPath: string;
29
+ shouldSkip: boolean;
30
+ };
31
+ /**
32
+ * Prepare Test 3: Check for TRIAL.json and TRIAL.env
33
+ */
34
+ export declare function prepareTest3(): {
35
+ envFile: string;
36
+ serviceKeyPath: string;
37
+ sapUrl: string;
38
+ shouldSkip: boolean;
39
+ };
40
+ /**
41
+ * Verify .env file contains required tokens
42
+ */
43
+ export declare function verifyEnvFile(envFile: string, requireRefreshToken?: boolean): void;
44
+ //# sourceMappingURL=testHelpers.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"testHelpers.d.ts","sourceRoot":"","sources":["../../src/__tests__/testHelpers.ts"],"names":[],"mappings":"AAAA;;GAEG;AAKH,OAAO,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAI3C,eAAO,MAAM,sBAAsB,QAAsF,CAAC;AAE1H,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,UAAU,CAAC;IACnB,sBAAsB,EAAE,UAAU,CAAC;CACpC;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,WAAW,CAM9D;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,WAAW,GAAG,IAAI,CAM7D;AAED;;GAEG;AACH,wBAAgB,iBAAiB,IAAI,OAAO,CAM3C;AAED;;GAEG;AACH,wBAAgB,YAAY,IAAI;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,cAAc,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,OAAO,CAAA;CAAE,CAe/F;AAED;;GAEG;AACH,wBAAgB,YAAY,IAAI;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,cAAc,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,OAAO,CAAA;CAAE,CAsB/G;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,OAAO,EAAE,MAAM,EAAE,mBAAmB,GAAE,OAAe,GAAG,IAAI,CAOzF"}