@mcp-abap-adt/auth-broker 0.2.9 → 0.2.10
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 +24 -0
- package/dist/AuthBroker.d.ts +35 -3
- package/dist/AuthBroker.d.ts.map +1 -1
- package/dist/AuthBroker.js +428 -339
- package/dist/__tests__/helpers/configHelpers.d.ts.map +1 -1
- package/dist/__tests__/helpers/configHelpers.js +4 -5
- package/dist/__tests__/helpers/testLogger.d.ts.map +1 -1
- package/dist/index.d.ts +3 -5
- package/dist/index.d.ts.map +1 -1
- package/dist/providers/ITokenProvider.d.ts +2 -2
- package/dist/providers/ITokenProvider.d.ts.map +1 -1
- package/dist/providers/index.d.ts +1 -1
- package/dist/providers/index.d.ts.map +1 -1
- package/dist/stores/index.d.ts +1 -1
- package/dist/stores/index.d.ts.map +1 -1
- package/dist/stores/interfaces.d.ts.map +1 -1
- package/dist/types.d.ts +1 -1
- package/dist/types.d.ts.map +1 -1
- package/package.json +7 -2
package/CHANGELOG.md
CHANGED
|
@@ -11,6 +11,30 @@ Thank you to all contributors! See [CONTRIBUTORS.md](CONTRIBUTORS.md) for the co
|
|
|
11
11
|
|
|
12
12
|
## [Unreleased]
|
|
13
13
|
|
|
14
|
+
## [0.2.10] - 2025-12-22
|
|
15
|
+
|
|
16
|
+
### Changed
|
|
17
|
+
- **Biome Migration**: Migrated from ESLint/Prettier to Biome for linting and formatting
|
|
18
|
+
- Added `@biomejs/biome` as dev dependency
|
|
19
|
+
- Added `lint`, `lint:check`, and `format` scripts to package.json
|
|
20
|
+
- Integrated Biome check into build process (`npx biome check src --diagnostic-level=error`)
|
|
21
|
+
- Replaced `unknown` with `any` in catch blocks (Biome requirement)
|
|
22
|
+
- Added `ErrorWithCode` type for better error type safety
|
|
23
|
+
- Refactored `getToken()` method into smaller private methods for better maintainability:
|
|
24
|
+
- `loadSessionData()` - loads session connection and authorization configs
|
|
25
|
+
- `getServiceUrl()` - gets serviceUrl from session or service key store
|
|
26
|
+
- `getUaaCredentials()` - gets UAA credentials from session or service key
|
|
27
|
+
- `saveTokenToSession()` - saves token and config to session
|
|
28
|
+
- `initializeSessionFromServiceKey()` - Step 0: initializes session from service key
|
|
29
|
+
- `validateExistingToken()` - Step 1: validates existing token
|
|
30
|
+
- `refreshTokenFromSession()` - Step 2a: refreshes token from session
|
|
31
|
+
- `refreshTokenFromServiceKey()` - Step 2b: refreshes token from service key
|
|
32
|
+
|
|
33
|
+
### Fixed
|
|
34
|
+
- Fixed type safety issues by replacing `unknown` with `any` in error handling
|
|
35
|
+
- Removed unnecessary type assertions by using `ErrorWithCode` type
|
|
36
|
+
- Improved code organization and readability through method extraction
|
|
37
|
+
|
|
14
38
|
## [0.2.9] - 2025-12-21
|
|
15
39
|
|
|
16
40
|
### Added
|
package/dist/AuthBroker.d.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Main AuthBroker class for managing JWT tokens based on destinations
|
|
3
3
|
*/
|
|
4
|
-
import { ILogger, ITokenRefresher } from '@mcp-abap-adt/interfaces';
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
4
|
+
import { type ILogger, type ITokenRefresher } from '@mcp-abap-adt/interfaces';
|
|
5
|
+
import type { ITokenProvider } from './providers';
|
|
6
|
+
import type { IAuthorizationConfig, IConnectionConfig, IServiceKeyStore, ISessionStore } from './stores/interfaces';
|
|
7
7
|
/**
|
|
8
8
|
* Configuration object for AuthBroker constructor
|
|
9
9
|
*/
|
|
@@ -44,6 +44,38 @@ export declare class AuthBroker {
|
|
|
44
44
|
* @param logger Optional logger instance implementing ILogger interface. If not provided, uses no-op logger.
|
|
45
45
|
*/
|
|
46
46
|
constructor(config: AuthBrokerConfig, browser?: string, logger?: ILogger);
|
|
47
|
+
/**
|
|
48
|
+
* Load session data (connection and authorization configs)
|
|
49
|
+
*/
|
|
50
|
+
private loadSessionData;
|
|
51
|
+
/**
|
|
52
|
+
* Get serviceUrl from session or service key store
|
|
53
|
+
*/
|
|
54
|
+
private getServiceUrl;
|
|
55
|
+
/**
|
|
56
|
+
* Get UAA credentials from session or service key
|
|
57
|
+
*/
|
|
58
|
+
private getUaaCredentials;
|
|
59
|
+
/**
|
|
60
|
+
* Save token and config to session
|
|
61
|
+
*/
|
|
62
|
+
private saveTokenToSession;
|
|
63
|
+
/**
|
|
64
|
+
* Initialize session from service key (Step 0)
|
|
65
|
+
*/
|
|
66
|
+
private initializeSessionFromServiceKey;
|
|
67
|
+
/**
|
|
68
|
+
* Validate existing token (Step 1)
|
|
69
|
+
*/
|
|
70
|
+
private validateExistingToken;
|
|
71
|
+
/**
|
|
72
|
+
* Refresh token from session (Step 2a)
|
|
73
|
+
*/
|
|
74
|
+
private refreshTokenFromSession;
|
|
75
|
+
/**
|
|
76
|
+
* Refresh token from service key (Step 2b)
|
|
77
|
+
*/
|
|
78
|
+
private refreshTokenFromServiceKey;
|
|
47
79
|
/**
|
|
48
80
|
* Get authentication token for destination.
|
|
49
81
|
* Uses tokenProvider for all authentication operations (browser-based authorization).
|
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,
|
|
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;IAyG7C;;OAEG;YACW,qBAAqB;IA8BnC;;OAEG;YACW,uBAAuB;IAwFrC;;OAEG;YACW,0BAA0B;IA8GxC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;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
|
@@ -14,6 +14,23 @@ const noOpLogger = {
|
|
|
14
14
|
warn: () => { },
|
|
15
15
|
debug: () => { },
|
|
16
16
|
};
|
|
17
|
+
/**
|
|
18
|
+
* Helper function to check if error has a code property
|
|
19
|
+
*/
|
|
20
|
+
// biome-ignore lint/suspicious/noExplicitAny: Helper function needs to accept any error type
|
|
21
|
+
function hasErrorCode(error) {
|
|
22
|
+
return (error !== null &&
|
|
23
|
+
typeof error === 'object' &&
|
|
24
|
+
'code' in error &&
|
|
25
|
+
typeof error.code === 'string');
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Helper function to get error message safely
|
|
29
|
+
*/
|
|
30
|
+
// biome-ignore lint/suspicious/noExplicitAny: Helper function needs to accept any error type
|
|
31
|
+
function getErrorMessage(error) {
|
|
32
|
+
return error instanceof Error ? error.message : String(error);
|
|
33
|
+
}
|
|
17
34
|
/**
|
|
18
35
|
* AuthBroker manages JWT authentication tokens for destinations
|
|
19
36
|
*/
|
|
@@ -94,82 +111,55 @@ class AuthBroker {
|
|
|
94
111
|
this.logger?.debug(`AuthBroker initialized: sessionStore(ok), serviceKeyStore(${hasServiceKeyStore ? 'ok' : 'none'}), tokenProvider(ok)`);
|
|
95
112
|
}
|
|
96
113
|
/**
|
|
97
|
-
*
|
|
98
|
-
* Uses tokenProvider for all authentication operations (browser-based authorization).
|
|
99
|
-
*
|
|
100
|
-
* **Flow:**
|
|
101
|
-
* **Step 0: Initialize Session with Token (if needed)**
|
|
102
|
-
* - Check if session has `authorizationToken` AND UAA credentials
|
|
103
|
-
* - If both are empty AND serviceKeyStore is available:
|
|
104
|
-
* - Get UAA credentials from service key
|
|
105
|
-
* - Use tokenProvider for browser-based authentication
|
|
106
|
-
* - Save token and refresh token to session
|
|
107
|
-
*
|
|
108
|
-
* **Step 1: Token Validation**
|
|
109
|
-
* - If token exists in session, validate it (if provider supports validation)
|
|
110
|
-
* - If valid → return token
|
|
111
|
-
* - If invalid or no token → continue to refresh
|
|
112
|
-
*
|
|
113
|
-
* **Step 2: Refresh Token Flow**
|
|
114
|
-
* - Check if refresh token exists in session
|
|
115
|
-
* - If refresh token exists:
|
|
116
|
-
* - Use tokenProvider to refresh token (browser-based or refresh grant)
|
|
117
|
-
* - Save new token to session
|
|
118
|
-
* - Return new token
|
|
119
|
-
* - Otherwise → proceed to Step 3
|
|
120
|
-
*
|
|
121
|
-
* **Step 3: New Token Flow**
|
|
122
|
-
* - Get UAA credentials from session or service key
|
|
123
|
-
* - Use tokenProvider for browser-based authentication
|
|
124
|
-
* - Save new token to session
|
|
125
|
-
* - Return new token
|
|
126
|
-
*
|
|
127
|
-
* **Important Notes:**
|
|
128
|
-
* - All authentication is handled by tokenProvider (e.g., XSUAA provider)
|
|
129
|
-
* - Provider uses browser-based authorization to ensure proper role assignment
|
|
130
|
-
* - Direct UAA HTTP requests are not used to avoid role assignment issues
|
|
131
|
-
*
|
|
132
|
-
* @param destination Destination name (e.g., "TRIAL")
|
|
133
|
-
* @returns Promise that resolves to JWT token string
|
|
134
|
-
* @throws Error if session initialization fails or authentication failed
|
|
114
|
+
* Load session data (connection and authorization configs)
|
|
135
115
|
*/
|
|
136
|
-
async
|
|
137
|
-
this.logger?.debug(`Getting token for destination: ${destination}`);
|
|
138
|
-
// Step 0: Initialize Session with Token (if needed)
|
|
116
|
+
async loadSessionData(destination) {
|
|
139
117
|
let connConfig = null;
|
|
140
118
|
let authConfig = null;
|
|
141
119
|
try {
|
|
142
120
|
connConfig = await this.sessionStore.getConnectionConfig(destination);
|
|
143
121
|
}
|
|
144
122
|
catch (error) {
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
123
|
+
if (hasErrorCode(error)) {
|
|
124
|
+
if (error.code === interfaces_1.STORE_ERROR_CODES.FILE_NOT_FOUND) {
|
|
125
|
+
this.logger?.debug(`Session file not found for ${destination}: ${error.filePath || 'unknown path'}`);
|
|
126
|
+
}
|
|
127
|
+
else if (error.code === interfaces_1.STORE_ERROR_CODES.PARSE_ERROR) {
|
|
128
|
+
this.logger?.warn(`Failed to parse session file for ${destination}: ${error.filePath || 'unknown path'} - ${getErrorMessage(error)}`);
|
|
129
|
+
}
|
|
130
|
+
else {
|
|
131
|
+
this.logger?.warn(`Failed to get connection config from session store for ${destination}: ${getErrorMessage(error)}`);
|
|
132
|
+
}
|
|
151
133
|
}
|
|
152
134
|
else {
|
|
153
|
-
this.logger?.warn(`Failed to get connection config from session store for ${destination}: ${error
|
|
135
|
+
this.logger?.warn(`Failed to get connection config from session store for ${destination}: ${getErrorMessage(error)}`);
|
|
154
136
|
}
|
|
155
137
|
}
|
|
156
138
|
try {
|
|
157
139
|
authConfig = await this.sessionStore.getAuthorizationConfig(destination);
|
|
158
140
|
}
|
|
159
141
|
catch (error) {
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
142
|
+
if (hasErrorCode(error)) {
|
|
143
|
+
if (error.code === interfaces_1.STORE_ERROR_CODES.FILE_NOT_FOUND) {
|
|
144
|
+
this.logger?.debug(`Session file not found for ${destination}: ${error.filePath || 'unknown path'}`);
|
|
145
|
+
}
|
|
146
|
+
else if (error.code === interfaces_1.STORE_ERROR_CODES.PARSE_ERROR) {
|
|
147
|
+
this.logger?.warn(`Failed to parse session file for ${destination}: ${error.filePath || 'unknown path'} - ${getErrorMessage(error)}`);
|
|
148
|
+
}
|
|
149
|
+
else {
|
|
150
|
+
this.logger?.warn(`Failed to get authorization config from session store for ${destination}: ${getErrorMessage(error)}`);
|
|
151
|
+
}
|
|
166
152
|
}
|
|
167
153
|
else {
|
|
168
|
-
this.logger?.warn(`Failed to get authorization config from session store for ${destination}: ${error
|
|
154
|
+
this.logger?.warn(`Failed to get authorization config from session store for ${destination}: ${getErrorMessage(error)}`);
|
|
169
155
|
}
|
|
170
156
|
}
|
|
171
|
-
|
|
172
|
-
|
|
157
|
+
return { connConfig, authConfig };
|
|
158
|
+
}
|
|
159
|
+
/**
|
|
160
|
+
* Get serviceUrl from session or service key store
|
|
161
|
+
*/
|
|
162
|
+
async getServiceUrl(destination, connConfig) {
|
|
173
163
|
let serviceUrl = connConfig?.serviceUrl;
|
|
174
164
|
if (!serviceUrl && this.serviceKeyStore) {
|
|
175
165
|
try {
|
|
@@ -180,15 +170,19 @@ class AuthBroker {
|
|
|
180
170
|
}
|
|
181
171
|
}
|
|
182
172
|
catch (error) {
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
173
|
+
if (hasErrorCode(error)) {
|
|
174
|
+
if (error.code === interfaces_1.STORE_ERROR_CODES.FILE_NOT_FOUND) {
|
|
175
|
+
this.logger?.debug(`Service key file not found for ${destination}: ${error.filePath || 'unknown path'}`);
|
|
176
|
+
}
|
|
177
|
+
else if (error.code === interfaces_1.STORE_ERROR_CODES.PARSE_ERROR) {
|
|
178
|
+
this.logger?.warn(`Failed to parse service key for ${destination}: ${error.filePath || 'unknown path'} - ${getErrorMessage(error)}`);
|
|
179
|
+
}
|
|
180
|
+
else {
|
|
181
|
+
this.logger?.warn(`Failed to get serviceUrl from service key store for ${destination}: ${getErrorMessage(error)}`);
|
|
182
|
+
}
|
|
189
183
|
}
|
|
190
184
|
else {
|
|
191
|
-
this.logger?.warn(`Failed to get serviceUrl from service key store for ${destination}: ${error
|
|
185
|
+
this.logger?.warn(`Failed to get serviceUrl from service key store for ${destination}: ${getErrorMessage(error)}`);
|
|
192
186
|
}
|
|
193
187
|
}
|
|
194
188
|
}
|
|
@@ -197,307 +191,388 @@ class AuthBroker {
|
|
|
197
191
|
throw new Error(`Session for destination "${destination}" is missing required field 'serviceUrl'. ` +
|
|
198
192
|
`SessionStore must contain initial session with serviceUrl${this.serviceKeyStore ? ' or serviceKeyStore must contain serviceUrl' : ''}.`);
|
|
199
193
|
}
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
`Provide serviceKeyStore to initialize from service key.`);
|
|
211
|
-
}
|
|
212
|
-
try {
|
|
213
|
-
// Get UAA credentials from service key
|
|
214
|
-
const serviceKeyAuthConfig = await this.serviceKeyStore.getAuthorizationConfig(destination);
|
|
215
|
-
if (!serviceKeyAuthConfig || !serviceKeyAuthConfig.uaaUrl || !serviceKeyAuthConfig.uaaClientId || !serviceKeyAuthConfig.uaaClientSecret) {
|
|
216
|
-
this.logger?.error(`Step 0: Service key for ${destination} missing UAA credentials`);
|
|
217
|
-
throw new Error(`Service key for destination "${destination}" does not contain UAA credentials`);
|
|
218
|
-
}
|
|
219
|
-
// Check if browser auth is allowed
|
|
220
|
-
if (!this.allowBrowserAuth) {
|
|
221
|
-
const error = new Error(`Browser authentication required for destination "${destination}" but allowBrowserAuth is disabled. ` +
|
|
222
|
-
`Either enable browser auth or provide a valid session with token.`);
|
|
223
|
-
error.code = 'BROWSER_AUTH_REQUIRED';
|
|
224
|
-
error.destination = destination;
|
|
225
|
-
this.logger?.error(`Step 0: Browser auth required but disabled for ${destination}`);
|
|
226
|
-
throw error;
|
|
227
|
-
}
|
|
228
|
-
// Use tokenProvider for browser-based authentication
|
|
229
|
-
this.logger?.debug(`Step 0: Authenticating via provider (browser) for ${destination} using service key UAA credentials`);
|
|
230
|
-
let tokenResult;
|
|
231
|
-
try {
|
|
232
|
-
tokenResult = await this.tokenProvider.getConnectionConfig(serviceKeyAuthConfig, {
|
|
233
|
-
browser: this.browser,
|
|
234
|
-
logger: this.logger,
|
|
235
|
-
});
|
|
236
|
-
}
|
|
237
|
-
catch (error) {
|
|
238
|
-
// Handle provider errors (network, auth, validation)
|
|
239
|
-
if (error.code === 'VALIDATION_ERROR') {
|
|
240
|
-
this.logger?.error(`Step 0: Provider validation error for ${destination}: missing ${error.missingFields?.join(', ') || 'required fields'}`);
|
|
241
|
-
throw new Error(`Cannot initialize session for destination "${destination}": provider validation failed - missing ${error.missingFields?.join(', ') || 'required fields'}`);
|
|
242
|
-
}
|
|
243
|
-
else if (error.code === 'BROWSER_AUTH_ERROR') {
|
|
244
|
-
this.logger?.error(`Step 0: Browser authentication failed for ${destination}: ${error.message}`);
|
|
245
|
-
throw new Error(`Cannot initialize session for destination "${destination}": browser authentication failed - ${error.message}`);
|
|
246
|
-
}
|
|
247
|
-
else if (error.code === 'ECONNREFUSED' || error.code === 'ETIMEDOUT' || error.code === 'ENOTFOUND') {
|
|
248
|
-
this.logger?.error(`Step 0: Network error for ${destination}: ${error.code}`);
|
|
249
|
-
throw new Error(`Cannot initialize session for destination "${destination}": network error - cannot reach authentication server (${error.code})`);
|
|
250
|
-
}
|
|
251
|
-
this.logger?.error(`Step 0: Provider error for ${destination}: ${error.message}`);
|
|
252
|
-
throw new Error(`Cannot initialize session for destination "${destination}": provider error - ${error.message}`);
|
|
253
|
-
}
|
|
254
|
-
const tokenLength = tokenResult.connectionConfig.authorizationToken?.length || 0;
|
|
255
|
-
this.logger?.info(`Step 0: Token initialized for ${destination}: token(${tokenLength} chars), hasRefreshToken(${!!tokenResult.refreshToken})`);
|
|
256
|
-
// Get serviceUrl from service key store if not in connectionConfig
|
|
257
|
-
const serviceKeyConnConfig = await this.serviceKeyStore.getConnectionConfig(destination);
|
|
258
|
-
const connectionConfigWithServiceUrl = {
|
|
259
|
-
...tokenResult.connectionConfig,
|
|
260
|
-
serviceUrl: tokenResult.connectionConfig.serviceUrl || serviceKeyConnConfig?.serviceUrl || serviceUrl,
|
|
261
|
-
};
|
|
262
|
-
// Save token and UAA credentials to session
|
|
263
|
-
try {
|
|
264
|
-
await this.sessionStore.setConnectionConfig(destination, connectionConfigWithServiceUrl);
|
|
265
|
-
}
|
|
266
|
-
catch (error) {
|
|
267
|
-
this.logger?.error(`Step 0: Failed to save connection config to session for ${destination}: ${error.message}`);
|
|
268
|
-
throw new Error(`Failed to save connection config for destination "${destination}": ${error.message}`);
|
|
269
|
-
}
|
|
270
|
-
try {
|
|
271
|
-
await this.sessionStore.setAuthorizationConfig(destination, {
|
|
272
|
-
...serviceKeyAuthConfig,
|
|
273
|
-
refreshToken: tokenResult.refreshToken || serviceKeyAuthConfig.refreshToken,
|
|
274
|
-
});
|
|
275
|
-
}
|
|
276
|
-
catch (error) {
|
|
277
|
-
this.logger?.error(`Step 0: Failed to save authorization config to session for ${destination}: ${error.message}`);
|
|
278
|
-
throw new Error(`Failed to save authorization config for destination "${destination}": ${error.message}`);
|
|
279
|
-
}
|
|
280
|
-
return tokenResult.connectionConfig.authorizationToken;
|
|
281
|
-
}
|
|
282
|
-
catch (error) {
|
|
283
|
-
// Re-throw BROWSER_AUTH_REQUIRED error without wrapping
|
|
284
|
-
if (error.code === 'BROWSER_AUTH_REQUIRED') {
|
|
285
|
-
throw error;
|
|
286
|
-
}
|
|
287
|
-
// Handle typed store errors
|
|
288
|
-
if (error.code === interfaces_1.STORE_ERROR_CODES.FILE_NOT_FOUND) {
|
|
289
|
-
this.logger?.error(`Step 0: Service key file not found for ${destination}: ${error.filePath || 'unknown path'}`);
|
|
290
|
-
throw new Error(`Cannot initialize session for destination "${destination}": service key file not found`);
|
|
291
|
-
}
|
|
292
|
-
else if (error.code === interfaces_1.STORE_ERROR_CODES.PARSE_ERROR) {
|
|
293
|
-
this.logger?.error(`Step 0: Failed to parse service key for ${destination}: ${error.filePath || 'unknown path'} - ${error.message}`);
|
|
294
|
-
throw new Error(`Cannot initialize session for destination "${destination}": service key parsing failed - ${error.message}`);
|
|
295
|
-
}
|
|
296
|
-
else if (error.code === interfaces_1.STORE_ERROR_CODES.INVALID_CONFIG) {
|
|
297
|
-
this.logger?.error(`Step 0: Invalid service key config for ${destination}: missing fields ${error.missingFields?.join(', ') || 'unknown'}`);
|
|
298
|
-
throw new Error(`Cannot initialize session for destination "${destination}": invalid service key - missing ${error.missingFields?.join(', ') || 'required fields'}`);
|
|
299
|
-
}
|
|
300
|
-
this.logger?.error(`Step 0: Failed to initialize session for ${destination}: ${error.message}`);
|
|
301
|
-
throw new Error(`Cannot initialize session for destination "${destination}": ${error.message}`);
|
|
302
|
-
}
|
|
194
|
+
return serviceUrl;
|
|
195
|
+
}
|
|
196
|
+
/**
|
|
197
|
+
* Get UAA credentials from session or service key
|
|
198
|
+
*/
|
|
199
|
+
async getUaaCredentials(destination, authConfig) {
|
|
200
|
+
if (authConfig?.uaaUrl &&
|
|
201
|
+
authConfig?.uaaClientId &&
|
|
202
|
+
authConfig?.uaaClientSecret) {
|
|
203
|
+
return authConfig;
|
|
303
204
|
}
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
this.logger?.debug(`Step 0: Token found for ${destination}, validating`);
|
|
307
|
-
// Validate token if provider supports validation and we have service URL
|
|
308
|
-
if (this.tokenProvider?.validateToken && serviceUrl) {
|
|
309
|
-
try {
|
|
310
|
-
const isValid = await this.tokenProvider.validateToken(connConfig.authorizationToken, serviceUrl);
|
|
311
|
-
if (isValid) {
|
|
312
|
-
this.logger?.info(`Step 0: Token valid for ${destination}: token(${connConfig.authorizationToken.length} chars)`);
|
|
313
|
-
return connConfig.authorizationToken;
|
|
314
|
-
}
|
|
315
|
-
this.logger?.debug(`Step 0: Token invalid for ${destination}, continuing to refresh`);
|
|
316
|
-
}
|
|
317
|
-
catch (error) {
|
|
318
|
-
// Validation failed due to network/server error - log and continue to refresh
|
|
319
|
-
this.logger?.warn(`Step 0: Token validation failed for ${destination} (network error): ${error.message}. Continuing to refresh.`);
|
|
320
|
-
// Don't throw - continue to refresh flow
|
|
321
|
-
}
|
|
322
|
-
}
|
|
323
|
-
else {
|
|
324
|
-
// No service URL or provider doesn't support validation - just return token
|
|
325
|
-
this.logger?.info(`Step 0: Token found for ${destination} (no validation): token(${connConfig.authorizationToken.length} chars)`);
|
|
326
|
-
return connConfig.authorizationToken;
|
|
327
|
-
}
|
|
205
|
+
if (!this.serviceKeyStore) {
|
|
206
|
+
throw new Error(`UAA credentials not found for ${destination}. Session has no UAA credentials and serviceKeyStore is not available.`);
|
|
328
207
|
}
|
|
329
|
-
// Step 2: Refresh Token Flow
|
|
330
|
-
this.logger?.debug(`Step 2: Attempting token refresh for ${destination}`);
|
|
331
|
-
// Get UAA credentials from session or service key
|
|
332
208
|
let serviceKeyAuthConfig = null;
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
209
|
+
try {
|
|
210
|
+
serviceKeyAuthConfig =
|
|
211
|
+
await this.serviceKeyStore.getAuthorizationConfig(destination);
|
|
212
|
+
}
|
|
213
|
+
catch (error) {
|
|
214
|
+
if (hasErrorCode(error)) {
|
|
339
215
|
if (error.code === interfaces_1.STORE_ERROR_CODES.FILE_NOT_FOUND) {
|
|
340
216
|
this.logger?.debug(`Service key file not found for ${destination}: ${error.filePath || 'unknown path'}`);
|
|
341
217
|
}
|
|
342
218
|
else if (error.code === interfaces_1.STORE_ERROR_CODES.PARSE_ERROR) {
|
|
343
|
-
this.logger?.warn(`Failed to parse service key for ${destination}: ${error.filePath || 'unknown path'} - ${error
|
|
219
|
+
this.logger?.warn(`Failed to parse service key for ${destination}: ${error.filePath || 'unknown path'} - ${getErrorMessage(error)}`);
|
|
344
220
|
}
|
|
345
221
|
else {
|
|
346
|
-
this.logger?.warn(`Failed to get UAA credentials from service key store for ${destination}: ${error
|
|
222
|
+
this.logger?.warn(`Failed to get UAA credentials from service key store for ${destination}: ${getErrorMessage(error)}`);
|
|
347
223
|
}
|
|
348
224
|
}
|
|
225
|
+
else {
|
|
226
|
+
this.logger?.warn(`Failed to get UAA credentials from service key store for ${destination}: ${getErrorMessage(error)}`);
|
|
227
|
+
}
|
|
349
228
|
}
|
|
350
229
|
const uaaCredentials = authConfig || serviceKeyAuthConfig;
|
|
351
|
-
if (!uaaCredentials ||
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
throw new Error(
|
|
230
|
+
if (!uaaCredentials ||
|
|
231
|
+
!uaaCredentials.uaaUrl ||
|
|
232
|
+
!uaaCredentials.uaaClientId ||
|
|
233
|
+
!uaaCredentials.uaaClientSecret) {
|
|
234
|
+
throw new Error(`UAA credentials not found for ${destination}. Session has no UAA credentials${this.serviceKeyStore ? ' and serviceKeyStore has no UAA credentials' : ' and serviceKeyStore is not available'}.`);
|
|
356
235
|
}
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
}
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
236
|
+
return uaaCredentials;
|
|
237
|
+
}
|
|
238
|
+
/**
|
|
239
|
+
* Save token and config to session
|
|
240
|
+
*/
|
|
241
|
+
async saveTokenToSession(destination, connectionConfig, authorizationConfig) {
|
|
242
|
+
try {
|
|
243
|
+
await this.sessionStore.setConnectionConfig(destination, connectionConfig);
|
|
244
|
+
}
|
|
245
|
+
catch (error) {
|
|
246
|
+
this.logger?.error(`Failed to save connection config to session for ${destination}: ${getErrorMessage(error)}`);
|
|
247
|
+
throw new Error(`Failed to save connection config for destination "${destination}": ${getErrorMessage(error)}`);
|
|
248
|
+
}
|
|
249
|
+
try {
|
|
250
|
+
await this.sessionStore.setAuthorizationConfig(destination, authorizationConfig);
|
|
251
|
+
}
|
|
252
|
+
catch (error) {
|
|
253
|
+
this.logger?.error(`Failed to save authorization config to session for ${destination}: ${getErrorMessage(error)}`);
|
|
254
|
+
throw new Error(`Failed to save authorization config for destination "${destination}": ${getErrorMessage(error)}`);
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
/**
|
|
258
|
+
* Initialize session from service key (Step 0)
|
|
259
|
+
*/
|
|
260
|
+
async initializeSessionFromServiceKey(destination, serviceUrl) {
|
|
261
|
+
if (!this.serviceKeyStore) {
|
|
262
|
+
throw new Error(`Cannot initialize session for destination "${destination}": authorizationToken is empty, UAA credentials are empty, and serviceKeyStore is not available. Provide serviceKeyStore to initialize from service key.`);
|
|
263
|
+
}
|
|
264
|
+
const serviceKeyAuthConfig = await this.serviceKeyStore.getAuthorizationConfig(destination);
|
|
265
|
+
if (!serviceKeyAuthConfig ||
|
|
266
|
+
!serviceKeyAuthConfig.uaaUrl ||
|
|
267
|
+
!serviceKeyAuthConfig.uaaClientId ||
|
|
268
|
+
!serviceKeyAuthConfig.uaaClientSecret) {
|
|
269
|
+
throw new Error(`Service key for destination "${destination}" does not contain UAA credentials`);
|
|
270
|
+
}
|
|
271
|
+
if (!this.allowBrowserAuth) {
|
|
272
|
+
const error = new Error(`Browser authentication required for destination "${destination}" but allowBrowserAuth is disabled. Either enable browser auth or provide a valid session with token.`);
|
|
273
|
+
error.code = 'BROWSER_AUTH_REQUIRED';
|
|
274
|
+
error.destination = destination;
|
|
275
|
+
this.logger?.error(`Step 0: Browser auth required but disabled for ${destination}`);
|
|
276
|
+
throw error;
|
|
277
|
+
}
|
|
278
|
+
this.logger?.debug(`Step 0: Authenticating via provider (browser) for ${destination} using service key UAA credentials`);
|
|
279
|
+
let tokenResult;
|
|
280
|
+
try {
|
|
281
|
+
tokenResult = await this.tokenProvider.getConnectionConfig(serviceKeyAuthConfig, {
|
|
282
|
+
browser: this.browser,
|
|
283
|
+
logger: this.logger,
|
|
284
|
+
});
|
|
285
|
+
}
|
|
286
|
+
catch (error) {
|
|
287
|
+
if (hasErrorCode(error)) {
|
|
288
|
+
if (error.code === 'VALIDATION_ERROR') {
|
|
289
|
+
throw new Error(`Cannot initialize session for destination "${destination}": provider validation failed - missing ${error.missingFields?.join(', ') || 'required fields'}`);
|
|
290
|
+
}
|
|
291
|
+
else if (error.code === 'BROWSER_AUTH_ERROR') {
|
|
292
|
+
throw new Error(`Cannot initialize session for destination "${destination}": browser authentication failed - ${getErrorMessage(error)}`);
|
|
293
|
+
}
|
|
294
|
+
else if (error.code === 'ECONNREFUSED' ||
|
|
295
|
+
error.code === 'ETIMEDOUT' ||
|
|
296
|
+
error.code === 'ENOTFOUND') {
|
|
297
|
+
throw new Error(`Cannot initialize session for destination "${destination}": network error - cannot reach authentication server (${error.code})`);
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
throw new Error(`Cannot initialize session for destination "${destination}": provider error - ${getErrorMessage(error)}`);
|
|
301
|
+
}
|
|
302
|
+
const token = tokenResult.connectionConfig.authorizationToken;
|
|
303
|
+
if (!token) {
|
|
304
|
+
throw new Error(`Token provider did not return authorization token for destination "${destination}"`);
|
|
305
|
+
}
|
|
306
|
+
const tokenLength = token.length;
|
|
307
|
+
this.logger?.info(`Step 0: Token initialized for ${destination}: token(${tokenLength} chars), hasRefreshToken(${!!tokenResult.refreshToken})`);
|
|
308
|
+
// Get serviceUrl from service key store if not in connectionConfig
|
|
309
|
+
const serviceKeyConnConfig = await this.serviceKeyStore.getConnectionConfig(destination);
|
|
310
|
+
const connectionConfigWithServiceUrl = {
|
|
311
|
+
...tokenResult.connectionConfig,
|
|
312
|
+
serviceUrl: tokenResult.connectionConfig.serviceUrl ||
|
|
313
|
+
serviceKeyConnConfig?.serviceUrl ||
|
|
314
|
+
serviceUrl,
|
|
315
|
+
};
|
|
316
|
+
await this.saveTokenToSession(destination, connectionConfigWithServiceUrl, {
|
|
317
|
+
...serviceKeyAuthConfig,
|
|
318
|
+
refreshToken: tokenResult.refreshToken || serviceKeyAuthConfig.refreshToken,
|
|
319
|
+
});
|
|
320
|
+
return token;
|
|
321
|
+
}
|
|
322
|
+
/**
|
|
323
|
+
* Validate existing token (Step 1)
|
|
324
|
+
*/
|
|
325
|
+
async validateExistingToken(destination, token, serviceUrl) {
|
|
326
|
+
if (!this.tokenProvider?.validateToken) {
|
|
327
|
+
return false;
|
|
328
|
+
}
|
|
329
|
+
try {
|
|
330
|
+
const isValid = await this.tokenProvider.validateToken(token, serviceUrl);
|
|
331
|
+
if (isValid) {
|
|
332
|
+
this.logger?.info(`Step 1: Token valid for ${destination}: token(${token.length} chars)`);
|
|
333
|
+
return true;
|
|
334
|
+
}
|
|
335
|
+
this.logger?.debug(`Step 1: Token invalid for ${destination}, continuing to refresh`);
|
|
336
|
+
return false;
|
|
337
|
+
}
|
|
338
|
+
catch (error) {
|
|
339
|
+
// Validation failed due to network/server error - log and continue to refresh
|
|
340
|
+
this.logger?.warn(`Step 1: Token validation failed for ${destination} (network error): ${getErrorMessage(error)}. Continuing to refresh.`);
|
|
341
|
+
return false;
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
/**
|
|
345
|
+
* Refresh token from session (Step 2a)
|
|
346
|
+
*/
|
|
347
|
+
async refreshTokenFromSession(destination, uaaCredentials, refreshToken, serviceUrl) {
|
|
348
|
+
this.logger?.debug(`Step 2a: Trying refreshTokenFromSession for ${destination}`);
|
|
349
|
+
const authConfigWithRefresh = { ...uaaCredentials, refreshToken };
|
|
350
|
+
let tokenResult;
|
|
351
|
+
try {
|
|
352
|
+
tokenResult = await this.tokenProvider.refreshTokenFromSession(authConfigWithRefresh, {
|
|
353
|
+
browser: this.browser,
|
|
354
|
+
logger: this.logger,
|
|
355
|
+
});
|
|
356
|
+
}
|
|
357
|
+
catch (error) {
|
|
358
|
+
if (hasErrorCode(error)) {
|
|
359
|
+
if (error.code === 'ECONNREFUSED' ||
|
|
360
|
+
error.code === 'ETIMEDOUT' ||
|
|
361
|
+
error.code === 'ENOTFOUND') {
|
|
362
|
+
this.logger?.debug(`Step 2a: Network error during refreshTokenFromSession for ${destination}: ${error.code}. Trying refreshTokenFromServiceKey`);
|
|
363
|
+
throw error; // Re-throw to trigger fallback to Step 2b
|
|
415
364
|
}
|
|
416
|
-
|
|
365
|
+
}
|
|
366
|
+
throw error; // Re-throw other errors
|
|
367
|
+
}
|
|
368
|
+
const token = tokenResult.connectionConfig.authorizationToken;
|
|
369
|
+
if (!token) {
|
|
370
|
+
throw new Error(`Token provider did not return authorization token for destination "${destination}"`);
|
|
371
|
+
}
|
|
372
|
+
const tokenLength = token.length;
|
|
373
|
+
this.logger?.info(`Step 2a: Token refreshed from session for ${destination}: token(${tokenLength} chars), hasRefreshToken(${!!tokenResult.refreshToken})`);
|
|
374
|
+
// Get serviceUrl from session or service key
|
|
375
|
+
let serviceKeyServiceUrl;
|
|
376
|
+
if (this.serviceKeyStore) {
|
|
377
|
+
try {
|
|
378
|
+
const serviceKeyConn = await this.serviceKeyStore.getConnectionConfig(destination);
|
|
379
|
+
serviceKeyServiceUrl = serviceKeyConn?.serviceUrl;
|
|
417
380
|
}
|
|
418
381
|
catch (error) {
|
|
419
|
-
this.logger?.debug(`
|
|
420
|
-
// Continue to try service key refresh
|
|
382
|
+
this.logger?.debug(`Could not get serviceUrl from service key store: ${getErrorMessage(error)}`);
|
|
421
383
|
}
|
|
422
384
|
}
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
385
|
+
const finalServiceUrl = tokenResult.connectionConfig.serviceUrl ||
|
|
386
|
+
serviceUrl ||
|
|
387
|
+
serviceKeyServiceUrl;
|
|
388
|
+
const connectionConfigWithServiceUrl = {
|
|
389
|
+
...tokenResult.connectionConfig,
|
|
390
|
+
serviceUrl: finalServiceUrl,
|
|
391
|
+
};
|
|
392
|
+
const authorizationConfig = {
|
|
393
|
+
...uaaCredentials,
|
|
394
|
+
refreshToken: tokenResult.refreshToken || refreshToken,
|
|
395
|
+
};
|
|
396
|
+
await this.saveTokenToSession(destination, connectionConfigWithServiceUrl, authorizationConfig);
|
|
397
|
+
return token;
|
|
398
|
+
}
|
|
399
|
+
/**
|
|
400
|
+
* Refresh token from service key (Step 2b)
|
|
401
|
+
*/
|
|
402
|
+
async refreshTokenFromServiceKey(destination, uaaCredentials, serviceUrl) {
|
|
428
403
|
if (!this.allowBrowserAuth) {
|
|
429
|
-
const error = new Error(`Browser authentication required for destination "${destination}" but allowBrowserAuth is disabled.
|
|
430
|
-
`Token refresh via session failed and browser auth is not allowed. ` +
|
|
431
|
-
`Either enable browser auth or ensure a valid refresh token exists in session.`);
|
|
404
|
+
const error = new Error(`Browser authentication required for destination "${destination}" but allowBrowserAuth is disabled. Token refresh via session failed and browser auth is not allowed. Either enable browser auth or ensure a valid refresh token exists in session.`);
|
|
432
405
|
error.code = 'BROWSER_AUTH_REQUIRED';
|
|
433
406
|
error.destination = destination;
|
|
434
407
|
this.logger?.error(`Step 2b: Browser auth required but disabled for ${destination}`);
|
|
435
408
|
throw error;
|
|
436
409
|
}
|
|
410
|
+
this.logger?.debug(`Step 2b: Trying refreshTokenFromServiceKey for ${destination}`);
|
|
411
|
+
let tokenResult;
|
|
437
412
|
try {
|
|
438
|
-
|
|
439
|
-
const tokenResult = await this.tokenProvider.refreshTokenFromServiceKey(uaaCredentials, {
|
|
413
|
+
tokenResult = await this.tokenProvider.refreshTokenFromServiceKey(uaaCredentials, {
|
|
440
414
|
browser: this.browser,
|
|
441
415
|
logger: this.logger,
|
|
442
416
|
});
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
try {
|
|
449
|
-
const serviceKeyConn = await this.serviceKeyStore.getConnectionConfig(destination);
|
|
450
|
-
serviceKeyServiceUrl = serviceKeyConn?.serviceUrl;
|
|
417
|
+
}
|
|
418
|
+
catch (error) {
|
|
419
|
+
if (hasErrorCode(error)) {
|
|
420
|
+
if (error.code === 'VALIDATION_ERROR') {
|
|
421
|
+
throw new Error(`Token refresh failed: Missing required fields in authConfig - ${error.missingFields?.join(', ')}`);
|
|
451
422
|
}
|
|
452
|
-
|
|
453
|
-
|
|
423
|
+
else if (error.code === 'BROWSER_AUTH_ERROR') {
|
|
424
|
+
throw new Error(`Token refresh failed: Browser authentication failed or was cancelled - ${getErrorMessage(error)}`);
|
|
425
|
+
}
|
|
426
|
+
else if (error.code === 'ECONNREFUSED' ||
|
|
427
|
+
error.code === 'ETIMEDOUT' ||
|
|
428
|
+
error.code === 'ENOTFOUND') {
|
|
429
|
+
throw new Error(`Token refresh failed: Network error - ${error.code}: Cannot reach authentication server`);
|
|
430
|
+
}
|
|
431
|
+
else if (error.code === 'SERVICE_KEY_ERROR') {
|
|
432
|
+
throw new Error(`Token refresh failed: Service key not found or invalid for ${destination}`);
|
|
454
433
|
}
|
|
455
434
|
}
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
};
|
|
461
|
-
|
|
435
|
+
throw new Error(`Token refresh failed for ${destination}: ${getErrorMessage(error)}`);
|
|
436
|
+
}
|
|
437
|
+
const token = tokenResult.connectionConfig.authorizationToken;
|
|
438
|
+
if (!token) {
|
|
439
|
+
throw new Error(`Token provider did not return authorization token for destination "${destination}"`);
|
|
440
|
+
}
|
|
441
|
+
const tokenLength = token.length;
|
|
442
|
+
this.logger?.info(`Step 2b: Token refreshed from service key for ${destination}: token(${tokenLength} chars), hasRefreshToken(${!!tokenResult.refreshToken})`);
|
|
443
|
+
// Get serviceUrl from session or service key
|
|
444
|
+
let serviceKeyServiceUrl;
|
|
445
|
+
if (this.serviceKeyStore) {
|
|
462
446
|
try {
|
|
463
|
-
await this.
|
|
447
|
+
const serviceKeyConn = await this.serviceKeyStore.getConnectionConfig(destination);
|
|
448
|
+
serviceKeyServiceUrl = serviceKeyConn?.serviceUrl;
|
|
464
449
|
}
|
|
465
450
|
catch (error) {
|
|
466
|
-
this.logger?.
|
|
467
|
-
throw new Error(`Failed to save connection config for destination "${destination}": ${error.message}`);
|
|
451
|
+
this.logger?.debug(`Could not get serviceUrl from service key store: ${getErrorMessage(error)}`);
|
|
468
452
|
}
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
453
|
+
}
|
|
454
|
+
const finalServiceUrl = tokenResult.connectionConfig.serviceUrl ||
|
|
455
|
+
serviceUrl ||
|
|
456
|
+
serviceKeyServiceUrl;
|
|
457
|
+
const connectionConfigWithServiceUrl = {
|
|
458
|
+
...tokenResult.connectionConfig,
|
|
459
|
+
serviceUrl: finalServiceUrl,
|
|
460
|
+
};
|
|
461
|
+
const authorizationConfig = {
|
|
462
|
+
...uaaCredentials,
|
|
463
|
+
refreshToken: tokenResult.refreshToken || uaaCredentials.refreshToken,
|
|
464
|
+
};
|
|
465
|
+
await this.saveTokenToSession(destination, connectionConfigWithServiceUrl, authorizationConfig);
|
|
466
|
+
return token;
|
|
467
|
+
}
|
|
468
|
+
/**
|
|
469
|
+
* Get authentication token for destination.
|
|
470
|
+
* Uses tokenProvider for all authentication operations (browser-based authorization).
|
|
471
|
+
*
|
|
472
|
+
* **Flow:**
|
|
473
|
+
* **Step 0: Initialize Session with Token (if needed)**
|
|
474
|
+
* - Check if session has `authorizationToken` AND UAA credentials
|
|
475
|
+
* - If both are empty AND serviceKeyStore is available:
|
|
476
|
+
* - Get UAA credentials from service key
|
|
477
|
+
* - Use tokenProvider for browser-based authentication
|
|
478
|
+
* - Save token and refresh token to session
|
|
479
|
+
*
|
|
480
|
+
* **Step 1: Token Validation**
|
|
481
|
+
* - If token exists in session, validate it (if provider supports validation)
|
|
482
|
+
* - If valid → return token
|
|
483
|
+
* - If invalid or no token → continue to refresh
|
|
484
|
+
*
|
|
485
|
+
* **Step 2: Refresh Token Flow**
|
|
486
|
+
* - Check if refresh token exists in session
|
|
487
|
+
* - If refresh token exists:
|
|
488
|
+
* - Use tokenProvider to refresh token (browser-based or refresh grant)
|
|
489
|
+
* - Save new token to session
|
|
490
|
+
* - Return new token
|
|
491
|
+
* - Otherwise → proceed to Step 3
|
|
492
|
+
*
|
|
493
|
+
* **Step 3: New Token Flow**
|
|
494
|
+
* - Get UAA credentials from session or service key
|
|
495
|
+
* - Use tokenProvider for browser-based authentication
|
|
496
|
+
* - Save new token to session
|
|
497
|
+
* - Return new token
|
|
498
|
+
*
|
|
499
|
+
* **Important Notes:**
|
|
500
|
+
* - All authentication is handled by tokenProvider (e.g., XSUAA provider)
|
|
501
|
+
* - Provider uses browser-based authorization to ensure proper role assignment
|
|
502
|
+
* - Direct UAA HTTP requests are not used to avoid role assignment issues
|
|
503
|
+
*
|
|
504
|
+
* @param destination Destination name (e.g., "TRIAL")
|
|
505
|
+
* @returns Promise that resolves to JWT token string
|
|
506
|
+
* @throws Error if session initialization fails or authentication failed
|
|
507
|
+
*/
|
|
508
|
+
async getToken(destination) {
|
|
509
|
+
this.logger?.debug(`Getting token for destination: ${destination}`);
|
|
510
|
+
// Load session data
|
|
511
|
+
const { connConfig, authConfig } = await this.loadSessionData(destination);
|
|
512
|
+
// Get serviceUrl (required)
|
|
513
|
+
const serviceUrl = await this.getServiceUrl(destination, connConfig);
|
|
514
|
+
// Check if we have token or UAA credentials
|
|
515
|
+
const hasToken = !!connConfig?.authorizationToken;
|
|
516
|
+
const hasUaaCredentials = !!(authConfig?.uaaUrl &&
|
|
517
|
+
authConfig?.uaaClientId &&
|
|
518
|
+
authConfig?.uaaClientSecret);
|
|
519
|
+
this.logger?.debug(`Session check for ${destination}: hasToken(${hasToken}), hasUaaCredentials(${hasUaaCredentials}), serviceUrl(${serviceUrl ? 'yes' : 'no'})`);
|
|
520
|
+
// Step 0: Initialize Session with Token (if needed)
|
|
521
|
+
if (!hasToken && !hasUaaCredentials) {
|
|
522
|
+
try {
|
|
523
|
+
return await this.initializeSessionFromServiceKey(destination, serviceUrl);
|
|
524
|
+
}
|
|
525
|
+
catch (error) {
|
|
526
|
+
// Re-throw BROWSER_AUTH_REQUIRED error without wrapping
|
|
527
|
+
if (hasErrorCode(error) && error.code === 'BROWSER_AUTH_REQUIRED') {
|
|
528
|
+
throw error;
|
|
475
529
|
}
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
530
|
+
// Handle typed store errors
|
|
531
|
+
if (hasErrorCode(error)) {
|
|
532
|
+
if (error.code === interfaces_1.STORE_ERROR_CODES.FILE_NOT_FOUND) {
|
|
533
|
+
throw new Error(`Cannot initialize session for destination "${destination}": service key file not found`);
|
|
534
|
+
}
|
|
535
|
+
else if (error.code === interfaces_1.STORE_ERROR_CODES.PARSE_ERROR) {
|
|
536
|
+
throw new Error(`Cannot initialize session for destination "${destination}": service key parsing failed - ${getErrorMessage(error)}`);
|
|
537
|
+
}
|
|
538
|
+
else if (error.code === interfaces_1.STORE_ERROR_CODES.INVALID_CONFIG) {
|
|
539
|
+
throw new Error(`Cannot initialize session for destination "${destination}": invalid service key - missing ${error.missingFields?.join(', ') || 'required fields'}`);
|
|
540
|
+
}
|
|
479
541
|
}
|
|
542
|
+
throw error;
|
|
480
543
|
}
|
|
481
|
-
return tokenResult.connectionConfig.authorizationToken;
|
|
482
544
|
}
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
if (
|
|
487
|
-
|
|
545
|
+
// Step 1: Validate existing token
|
|
546
|
+
if (hasToken && connConfig?.authorizationToken) {
|
|
547
|
+
const isValid = await this.validateExistingToken(destination, connConfig.authorizationToken, serviceUrl);
|
|
548
|
+
if (isValid) {
|
|
549
|
+
return connConfig.authorizationToken;
|
|
488
550
|
}
|
|
489
|
-
|
|
490
|
-
|
|
551
|
+
// If no validation or validation failed, continue to refresh
|
|
552
|
+
if (!this.tokenProvider?.validateToken) {
|
|
553
|
+
this.logger?.info(`Token found for ${destination} (no validation): token(${connConfig.authorizationToken.length} chars)`);
|
|
554
|
+
return connConfig.authorizationToken;
|
|
491
555
|
}
|
|
492
|
-
|
|
493
|
-
|
|
556
|
+
}
|
|
557
|
+
// Step 2: Refresh Token Flow
|
|
558
|
+
this.logger?.debug(`Step 2: Attempting token refresh for ${destination}`);
|
|
559
|
+
const uaaCredentials = await this.getUaaCredentials(destination, authConfig);
|
|
560
|
+
// Step 2a: Try refresh from session (if refresh token exists)
|
|
561
|
+
const refreshToken = authConfig?.refreshToken;
|
|
562
|
+
if (refreshToken) {
|
|
563
|
+
try {
|
|
564
|
+
return await this.refreshTokenFromSession(destination, uaaCredentials, refreshToken, serviceUrl);
|
|
494
565
|
}
|
|
495
|
-
|
|
496
|
-
|
|
566
|
+
catch (error) {
|
|
567
|
+
this.logger?.debug(`Step 2a: refreshTokenFromSession failed for ${destination}: ${getErrorMessage(error)}, trying refreshTokenFromServiceKey`);
|
|
568
|
+
// Continue to try service key refresh
|
|
497
569
|
}
|
|
498
|
-
// Generic error
|
|
499
|
-
throw new Error(`Token refresh failed for ${destination}: ${error.message}`);
|
|
500
570
|
}
|
|
571
|
+
else {
|
|
572
|
+
this.logger?.debug(`Step 2a: No refresh token in session for ${destination}, skipping to service key refresh`);
|
|
573
|
+
}
|
|
574
|
+
// Step 2b: Try refresh from service key (browser authentication)
|
|
575
|
+
return await this.refreshTokenFromServiceKey(destination, uaaCredentials, serviceUrl);
|
|
501
576
|
}
|
|
502
577
|
/**
|
|
503
578
|
* Force refresh token for destination.
|
|
@@ -521,10 +596,11 @@ class AuthBroker {
|
|
|
521
596
|
this.logger?.debug(`Checking session store for authorization config: ${destination}`);
|
|
522
597
|
let sessionAuthConfig = null;
|
|
523
598
|
try {
|
|
524
|
-
sessionAuthConfig =
|
|
599
|
+
sessionAuthConfig =
|
|
600
|
+
await this.sessionStore.getAuthorizationConfig(destination);
|
|
525
601
|
}
|
|
526
602
|
catch (error) {
|
|
527
|
-
this.logger?.warn(`Failed to get authorization config from session store for ${destination}: ${error
|
|
603
|
+
this.logger?.warn(`Failed to get authorization config from session store for ${destination}: ${getErrorMessage(error)}`);
|
|
528
604
|
}
|
|
529
605
|
if (sessionAuthConfig) {
|
|
530
606
|
this.logger?.debug(`Authorization config from session for ${destination}: hasUaaUrl(${!!sessionAuthConfig.uaaUrl}), hasRefreshToken(${!!sessionAuthConfig.refreshToken})`);
|
|
@@ -535,18 +611,24 @@ class AuthBroker {
|
|
|
535
611
|
this.logger?.debug(`Checking service key store for authorization config: ${destination}`);
|
|
536
612
|
let serviceKeyAuthConfig = null;
|
|
537
613
|
try {
|
|
538
|
-
serviceKeyAuthConfig =
|
|
614
|
+
serviceKeyAuthConfig =
|
|
615
|
+
await this.serviceKeyStore.getAuthorizationConfig(destination);
|
|
539
616
|
}
|
|
540
617
|
catch (error) {
|
|
541
618
|
// Handle typed store errors
|
|
542
|
-
if (error
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
619
|
+
if (hasErrorCode(error)) {
|
|
620
|
+
if (error.code === interfaces_1.STORE_ERROR_CODES.FILE_NOT_FOUND) {
|
|
621
|
+
this.logger?.debug(`Service key file not found for ${destination}: ${error.filePath || 'unknown path'}`);
|
|
622
|
+
}
|
|
623
|
+
else if (error.code === interfaces_1.STORE_ERROR_CODES.PARSE_ERROR) {
|
|
624
|
+
this.logger?.warn(`Failed to parse service key for ${destination}: ${error.filePath || 'unknown path'} - ${getErrorMessage(error)}`);
|
|
625
|
+
}
|
|
626
|
+
else {
|
|
627
|
+
this.logger?.warn(`Failed to get authorization config from service key store for ${destination}: ${getErrorMessage(error)}`);
|
|
628
|
+
}
|
|
547
629
|
}
|
|
548
630
|
else {
|
|
549
|
-
this.logger?.warn(`Failed to get authorization config from service key store for ${destination}: ${error
|
|
631
|
+
this.logger?.warn(`Failed to get authorization config from service key store for ${destination}: ${getErrorMessage(error)}`);
|
|
550
632
|
}
|
|
551
633
|
}
|
|
552
634
|
if (serviceKeyAuthConfig) {
|
|
@@ -570,10 +652,11 @@ class AuthBroker {
|
|
|
570
652
|
// Try session store first (has tokens and URLs)
|
|
571
653
|
let sessionConnConfig = null;
|
|
572
654
|
try {
|
|
573
|
-
sessionConnConfig =
|
|
655
|
+
sessionConnConfig =
|
|
656
|
+
await this.sessionStore.getConnectionConfig(destination);
|
|
574
657
|
}
|
|
575
658
|
catch (error) {
|
|
576
|
-
this.logger?.warn(`Failed to get connection config from session store for ${destination}: ${error
|
|
659
|
+
this.logger?.warn(`Failed to get connection config from session store for ${destination}: ${getErrorMessage(error)}`);
|
|
577
660
|
}
|
|
578
661
|
if (sessionConnConfig) {
|
|
579
662
|
this.logger?.debug(`Connection config from session for ${destination}: token(${sessionConnConfig.authorizationToken?.length || 0} chars), serviceUrl(${sessionConnConfig.serviceUrl ? 'yes' : 'no'})`);
|
|
@@ -583,18 +666,24 @@ class AuthBroker {
|
|
|
583
666
|
if (this.serviceKeyStore) {
|
|
584
667
|
let serviceKeyConnConfig = null;
|
|
585
668
|
try {
|
|
586
|
-
serviceKeyConnConfig =
|
|
669
|
+
serviceKeyConnConfig =
|
|
670
|
+
await this.serviceKeyStore.getConnectionConfig(destination);
|
|
587
671
|
}
|
|
588
672
|
catch (error) {
|
|
589
673
|
// Handle typed store errors
|
|
590
|
-
if (error
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
674
|
+
if (hasErrorCode(error)) {
|
|
675
|
+
if (error.code === interfaces_1.STORE_ERROR_CODES.FILE_NOT_FOUND) {
|
|
676
|
+
this.logger?.debug(`Service key file not found for ${destination}: ${error.filePath || 'unknown path'}`);
|
|
677
|
+
}
|
|
678
|
+
else if (error.code === interfaces_1.STORE_ERROR_CODES.PARSE_ERROR) {
|
|
679
|
+
this.logger?.warn(`Failed to parse service key for ${destination}: ${error.filePath || 'unknown path'} - ${getErrorMessage(error)}`);
|
|
680
|
+
}
|
|
681
|
+
else {
|
|
682
|
+
this.logger?.warn(`Failed to get connection config from service key store for ${destination}: ${getErrorMessage(error)}`);
|
|
683
|
+
}
|
|
595
684
|
}
|
|
596
685
|
else {
|
|
597
|
-
this.logger?.warn(`Failed to get connection config from service key store for ${destination}: ${error
|
|
686
|
+
this.logger?.warn(`Failed to get connection config from service key store for ${destination}: ${getErrorMessage(error)}`);
|
|
598
687
|
}
|
|
599
688
|
}
|
|
600
689
|
if (serviceKeyConnConfig) {
|
|
@@ -641,7 +730,7 @@ class AuthBroker {
|
|
|
641
730
|
*/
|
|
642
731
|
async refreshToken() {
|
|
643
732
|
return broker.refreshToken(destination);
|
|
644
|
-
}
|
|
733
|
+
},
|
|
645
734
|
};
|
|
646
735
|
}
|
|
647
736
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"configHelpers.d.ts","sourceRoot":"","sources":["../../../src/__tests__/helpers/configHelpers.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAQH,MAAM,WAAW,UAAU;IACzB,WAAW,CAAC,EAAE;QACZ,KAAK,CAAC,EAAE;YACN,gBAAgB,CAAC,EAAE,MAAM,CAAC;YAC1B,YAAY,CAAC,EAAE,MAAM,CAAC;SACvB,CAAC;QACF,IAAI,CAAC,EAAE;YACL,WAAW,CAAC,EAAE,MAAM,CAAC;SACtB,CAAC;QACF,KAAK,CAAC,EAAE;YACN,eAAe,CAAC,EAAE,MAAM,CAAC;YACzB,eAAe,CAAC,EAAE,MAAM,CAAC;YACzB,OAAO,CAAC,EAAE,MAAM,CAAC;SAClB,CAAC;KACH,CAAC;CACH;AAkBD;;;GAGG;AACH,wBAAgB,cAAc,IAAI,UAAU,
|
|
1
|
+
{"version":3,"file":"configHelpers.d.ts","sourceRoot":"","sources":["../../../src/__tests__/helpers/configHelpers.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAQH,MAAM,WAAW,UAAU;IACzB,WAAW,CAAC,EAAE;QACZ,KAAK,CAAC,EAAE;YACN,gBAAgB,CAAC,EAAE,MAAM,CAAC;YAC1B,YAAY,CAAC,EAAE,MAAM,CAAC;SACvB,CAAC;QACF,IAAI,CAAC,EAAE;YACL,WAAW,CAAC,EAAE,MAAM,CAAC;SACtB,CAAC;QACF,KAAK,CAAC,EAAE;YACN,eAAe,CAAC,EAAE,MAAM,CAAC;YACzB,eAAe,CAAC,EAAE,MAAM,CAAC;YACzB,OAAO,CAAC,EAAE,MAAM,CAAC;SAClB,CAAC;KACH,CAAC;CACH;AAkBD;;;GAGG;AACH,wBAAgB,cAAc,IAAI,UAAU,CAyD3C;AAED;;GAEG;AACH,wBAAgB,aAAa,CAC3B,MAAM,EAAE,UAAU,EAClB,OAAO,EAAE,MAAM,GAAG,OAAO,GACxB,OAAO,CAwBT;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,CAAC,EAAE,UAAU,GAAG,MAAM,GAAG,IAAI,CAGrE;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,CAAC,EAAE,UAAU,GAAG;IACzD,eAAe,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;CACxB,CAOA;AAaD;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,CAAC,EAAE,UAAU,GAAG,MAAM,GAAG,IAAI,CASpE;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,MAAM,CAAC,EAAE,UAAU,GAAG,MAAM,GAAG,IAAI,CASjE"}
|
|
@@ -43,8 +43,8 @@ exports.getAbapDestination = getAbapDestination;
|
|
|
43
43
|
exports.getXsuaaDestinations = getXsuaaDestinations;
|
|
44
44
|
exports.getServiceKeysDir = getServiceKeysDir;
|
|
45
45
|
exports.getSessionsDir = getSessionsDir;
|
|
46
|
-
const fs = __importStar(require("fs"));
|
|
47
|
-
const path = __importStar(require("path"));
|
|
46
|
+
const fs = __importStar(require("node:fs"));
|
|
47
|
+
const path = __importStar(require("node:path"));
|
|
48
48
|
const yaml = __importStar(require("js-yaml"));
|
|
49
49
|
let cachedConfig = null;
|
|
50
50
|
/**
|
|
@@ -130,8 +130,7 @@ function hasRealConfig(config, section) {
|
|
|
130
130
|
return false;
|
|
131
131
|
}
|
|
132
132
|
// Check if values are not placeholders
|
|
133
|
-
return
|
|
134
|
-
!xsuaa.mcp_url.includes('<'));
|
|
133
|
+
return !xsuaa.btp_destination.includes('<') && !xsuaa.mcp_url.includes('<');
|
|
135
134
|
}
|
|
136
135
|
return false;
|
|
137
136
|
}
|
|
@@ -158,7 +157,7 @@ function getXsuaaDestinations(config) {
|
|
|
158
157
|
*/
|
|
159
158
|
function expandTilde(filePath) {
|
|
160
159
|
if (filePath.startsWith('~')) {
|
|
161
|
-
const os = require('os');
|
|
160
|
+
const os = require('node:os');
|
|
162
161
|
return path.join(os.homedir(), filePath.slice(1));
|
|
163
162
|
}
|
|
164
163
|
return filePath;
|
|
@@ -1 +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,
|
|
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,CAkEjE"}
|
package/dist/index.d.ts
CHANGED
|
@@ -2,11 +2,9 @@
|
|
|
2
2
|
* @mcp-abap-adt/auth-broker
|
|
3
3
|
* JWT authentication broker for MCP ABAP ADT server
|
|
4
4
|
*/
|
|
5
|
+
export type { AuthType, ILogger, ITokenRefresher, } from '@mcp-abap-adt/interfaces';
|
|
5
6
|
export { AuthBroker, type AuthBrokerConfig } from './AuthBroker';
|
|
6
|
-
export type {
|
|
7
|
+
export type { ITokenProvider, TokenProviderOptions, TokenProviderResult, } from './providers';
|
|
8
|
+
export type { IAuthorizationConfig, IConnectionConfig, IServiceKeyStore, ISessionStore, } from './stores/interfaces';
|
|
7
9
|
export type { IConfig } from './types';
|
|
8
|
-
export type { ITokenProvider, TokenProviderOptions, TokenProviderResult } from './providers';
|
|
9
|
-
export type { ITokenRefresher } from '@mcp-abap-adt/interfaces';
|
|
10
|
-
export type { ILogger } from '@mcp-abap-adt/interfaces';
|
|
11
|
-
export type { AuthType } from '@mcp-abap-adt/interfaces';
|
|
12
10
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAKH,YAAY,EACV,QAAQ,EACR,OAAO,EACP,eAAe,GAChB,MAAM,0BAA0B,CAAC;AAClC,OAAO,EAAE,UAAU,EAAE,KAAK,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAEjE,YAAY,EACV,cAAc,EACd,oBAAoB,EACpB,mBAAmB,GACpB,MAAM,aAAa,CAAC;AAGrB,YAAY,EACV,oBAAoB,EACpB,iBAAiB,EACjB,gBAAgB,EAChB,aAAa,GACd,MAAM,qBAAqB,CAAC;AAC7B,YAAY,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC"}
|
|
@@ -6,8 +6,8 @@
|
|
|
6
6
|
* - XSUAA: client_credentials grant type (no browser)
|
|
7
7
|
* - BTP/ABAP: browser-based OAuth2 or refresh token
|
|
8
8
|
*/
|
|
9
|
-
import type { IAuthorizationConfig, IConnectionConfig, ITokenProvider,
|
|
10
|
-
export type { ITokenProvider, IAuthorizationConfig, IConnectionConfig
|
|
9
|
+
import type { IAuthorizationConfig, IConnectionConfig, ITokenProvider, ITokenProviderOptions, ITokenProviderResult } from '@mcp-abap-adt/interfaces';
|
|
10
|
+
export type { ITokenProvider, IAuthorizationConfig, IConnectionConfig };
|
|
11
11
|
export type TokenProviderResult = ITokenProviderResult;
|
|
12
12
|
export type TokenProviderOptions = ITokenProviderOptions;
|
|
13
13
|
//# sourceMappingURL=ITokenProvider.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ITokenProvider.d.ts","sourceRoot":"","sources":["../../src/providers/ITokenProvider.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAGH,OAAO,KAAK,EACV,oBAAoB,EACpB,iBAAiB,EACjB,cAAc,EACd,
|
|
1
|
+
{"version":3,"file":"ITokenProvider.d.ts","sourceRoot":"","sources":["../../src/providers/ITokenProvider.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAGH,OAAO,KAAK,EACV,oBAAoB,EACpB,iBAAiB,EACjB,cAAc,EACd,qBAAqB,EACrB,oBAAoB,EACrB,MAAM,0BAA0B,CAAC;AAGlC,YAAY,EAAE,cAAc,EAAE,oBAAoB,EAAE,iBAAiB,EAAE,CAAC;AACxE,MAAM,MAAM,mBAAmB,GAAG,oBAAoB,CAAC;AACvD,MAAM,MAAM,oBAAoB,GAAG,qBAAqB,CAAC"}
|
|
@@ -4,5 +4,5 @@
|
|
|
4
4
|
* Provider implementations are in separate packages:
|
|
5
5
|
* - @mcp-abap-adt/auth-providers - XSUAA and BTP providers
|
|
6
6
|
*/
|
|
7
|
-
export type { ITokenProvider, TokenProviderOptions, TokenProviderResult } from './ITokenProvider';
|
|
7
|
+
export type { ITokenProvider, TokenProviderOptions, TokenProviderResult, } from './ITokenProvider';
|
|
8
8
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/providers/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,YAAY,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/providers/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,YAAY,EACV,cAAc,EACd,oBAAoB,EACpB,mBAAmB,GACpB,MAAM,kBAAkB,CAAC"}
|
package/dist/stores/index.d.ts
CHANGED
|
@@ -4,5 +4,5 @@
|
|
|
4
4
|
* Store implementations are in separate packages:
|
|
5
5
|
* - @mcp-abap-adt/auth-stores-btp - BTP and ABAP stores
|
|
6
6
|
*/
|
|
7
|
-
export type {
|
|
7
|
+
export type { IAuthorizationConfig, IConnectionConfig, IServiceKeyStore, ISessionStore, } from './interfaces';
|
|
8
8
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/stores/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,YAAY,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/stores/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,YAAY,EACV,oBAAoB,EACpB,iBAAiB,EACjB,gBAAgB,EAChB,aAAa,GACd,MAAM,cAAc,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"interfaces.d.ts","sourceRoot":"","sources":["../../src/stores/interfaces.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,KAAK,EACV,oBAAoB,EACpB,iBAAiB,EACjB,gBAAgB,EAChB,aAAa,
|
|
1
|
+
{"version":3,"file":"interfaces.d.ts","sourceRoot":"","sources":["../../src/stores/interfaces.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,KAAK,EACV,oBAAoB,EACpB,iBAAiB,EACjB,gBAAgB,EAChB,aAAa,EACd,MAAM,0BAA0B,CAAC;AAGlC,YAAY,EACV,oBAAoB,EACpB,iBAAiB,EACjB,gBAAgB,EAChB,aAAa,GACd,CAAC"}
|
package/dist/types.d.ts
CHANGED
|
@@ -3,6 +3,6 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Type aliases (type) are defined here. Interfaces are imported from @mcp-abap-adt/interfaces.
|
|
5
5
|
*/
|
|
6
|
-
import type { IAuthorizationConfig,
|
|
6
|
+
import type { IAuthorizationConfig, IConfig, IConnectionConfig, IServiceKeyStore, ISessionStore } from '@mcp-abap-adt/interfaces';
|
|
7
7
|
export type { IConfig, IAuthorizationConfig, IConnectionConfig, IServiceKeyStore, ISessionStore, };
|
|
8
8
|
//# sourceMappingURL=types.d.ts.map
|
package/dist/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,KAAK,EACV,oBAAoB,EACpB,iBAAiB,EACjB,
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,KAAK,EACV,oBAAoB,EACpB,OAAO,EACP,iBAAiB,EACjB,gBAAgB,EAChB,aAAa,EACd,MAAM,0BAA0B,CAAC;AAGlC,YAAY,EACV,OAAO,EACP,oBAAoB,EACpB,iBAAiB,EACjB,gBAAgB,EAChB,aAAa,GACd,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mcp-abap-adt/auth-broker",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.10",
|
|
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",
|
|
@@ -36,8 +36,12 @@
|
|
|
36
36
|
"access": "public"
|
|
37
37
|
},
|
|
38
38
|
"scripts": {
|
|
39
|
+
"chrono": "./tools/version-stats.sh",
|
|
39
40
|
"clean": "rm -rf dist tsconfig.tsbuildinfo",
|
|
40
|
-
"
|
|
41
|
+
"lint": "npx biome check --write src",
|
|
42
|
+
"lint:check": "npx biome check src",
|
|
43
|
+
"format": "npx biome format --write src",
|
|
44
|
+
"build": "npm run --silent clean && npx biome check src --diagnostic-level=error && npx tsc -p tsconfig.json",
|
|
41
45
|
"build:fast": "npx tsc -p tsconfig.json",
|
|
42
46
|
"test": "NODE_OPTIONS=--experimental-vm-modules jest",
|
|
43
47
|
"test:check": "npx tsc --noEmit && npx tsc --noEmit -p tsconfig.test.json",
|
|
@@ -55,6 +59,7 @@
|
|
|
55
59
|
"axios": "^1.13.2"
|
|
56
60
|
},
|
|
57
61
|
"devDependencies": {
|
|
62
|
+
"@biomejs/biome": "^2.3.10",
|
|
58
63
|
"@mcp-abap-adt/auth-providers": "^0.2.4",
|
|
59
64
|
"@mcp-abap-adt/auth-stores": "^0.2.8",
|
|
60
65
|
"@types/express": "^5.0.5",
|