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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -7,6 +7,40 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [0.2.0] - 2025-12-19
11
+
12
+ ### Added
13
+ - **Typed Error Classes**: Added specialized error classes for better error handling and debugging
14
+ - `TokenProviderError` - Base class for all token provider errors with error code
15
+ - `ValidationError` - Thrown when authConfig validation fails (includes `missingFields: string[]` array)
16
+ - `RefreshError` - Thrown when token refresh operation fails (includes `cause?: Error` with original error)
17
+ - `SessionDataError` - Thrown when session data is invalid or incomplete (includes `missingFields` array)
18
+ - `ServiceKeyError` - Thrown when service key data is invalid or incomplete (includes `missingFields` array)
19
+ - `BrowserAuthError` - Thrown when browser authentication fails or is cancelled (includes `cause` error)
20
+ - All error codes use constants from `@mcp-abap-adt/interfaces` package (`TOKEN_PROVIDER_ERROR_CODES`)
21
+ - Errors are exported from package root for easy import
22
+
23
+ ### Changed
24
+ - **Enhanced Validation Error Messages**: Validation errors now list specific missing field names instead of generic messages
25
+ - Example: `XSUAA refreshTokenFromSession: authConfig missing required fields: uaaUrl, uaaClientId`
26
+ - `ValidationError` includes `missingFields: string[]` property for programmatic access to missing fields
27
+ - Each missing field is checked individually and added to the list
28
+ - **Improved Error Handling in Refresh Methods**: All refresh operations now wrap errors with typed error classes
29
+ - `refreshTokenFromSession` throws `RefreshError` when client_credentials or browser auth fails
30
+ - `refreshTokenFromServiceKey` throws `RefreshError` when browser authentication fails
31
+ - Original error is preserved in `RefreshError.cause` property for debugging
32
+ - Error messages include provider type (XSUAA/BTP) and operation name for clarity
33
+ - **Dependency Update**: Updated `@mcp-abap-adt/interfaces` to `^0.2.2` for `TOKEN_PROVIDER_ERROR_CODES` constants
34
+ - **Test Coverage**: Added tests for error handling edge cases
35
+ - Tests verify `RefreshError` is thrown when authentication fails
36
+ - Tests verify `ValidationError` includes correct missing field names
37
+ - Tests verify error messages contain expected substrings
38
+
39
+ ## [0.1.5] - 2025-12-13
40
+
41
+ ### Changed
42
+ - Dependency bump: `@mcp-abap-adt/interfaces` to `^0.1.16` to align with latest interfaces release
43
+
10
44
  ## [0.1.4] - 2025-12-08
11
45
 
12
46
  ### Added
@@ -134,4 +168,3 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
134
168
  - `@mcp-abap-adt/auth-stores` ^0.1.2 - Store implementations
135
169
  - `@mcp-abap-adt/connection` ^0.1.13 - Connection utilities
136
170
  - `@mcp-abap-adt/logger` ^0.1.0 - Logging utilities
137
-
package/README.md CHANGED
@@ -207,6 +207,104 @@ const isValid = await provider.validateToken(token, serviceUrl);
207
207
  // Returns true if token is valid (200-299 status), false otherwise
208
208
  ```
209
209
 
210
+ ### Token Refresh Methods
211
+
212
+ Both providers implement two refresh methods from `ITokenProvider` interface:
213
+
214
+ #### refreshTokenFromSession
215
+
216
+ Refreshes token using existing session data (with refreshToken):
217
+
218
+ ```typescript
219
+ import { XsuaaTokenProvider } from '@mcp-abap-adt/auth-providers';
220
+ import { ValidationError, RefreshError } from '@mcp-abap-adt/auth-providers';
221
+
222
+ const provider = new XsuaaTokenProvider();
223
+
224
+ const authConfig: IAuthorizationConfig = {
225
+ uaaUrl: 'https://...authentication...hana.ondemand.com',
226
+ uaaClientId: '...',
227
+ uaaClientSecret: '...',
228
+ refreshToken: '...', // From existing session
229
+ };
230
+
231
+ try {
232
+ const result = await provider.refreshTokenFromSession(authConfig);
233
+ // XSUAA uses client_credentials - no refresh token in response
234
+ // BTP uses browser auth - returns new refresh token
235
+ } catch (error) {
236
+ if (error instanceof ValidationError) {
237
+ // authConfig missing required fields
238
+ console.error('Missing fields:', error.missingFields); // ['uaaUrl', 'uaaClientId', ...]
239
+ } else if (error instanceof RefreshError) {
240
+ // Token refresh failed
241
+ console.error('Refresh failed:', error.message);
242
+ console.error('Original error:', error.cause);
243
+ }
244
+ }
245
+ ```
246
+
247
+ #### refreshTokenFromServiceKey
248
+
249
+ Refreshes token using service key credentials (without refreshToken):
250
+
251
+ ```typescript
252
+ try {
253
+ const result = await provider.refreshTokenFromServiceKey(authConfig);
254
+ // Both XSUAA and BTP use browser authentication for service key refresh
255
+ // Returns new access token and refresh token
256
+ } catch (error) {
257
+ if (error instanceof ValidationError) {
258
+ console.error('Missing fields:', error.missingFields);
259
+ } else if (error instanceof RefreshError) {
260
+ console.error('Browser auth failed:', error.cause);
261
+ }
262
+ }
263
+ ```
264
+
265
+ ### Error Handling
266
+
267
+ The package provides typed error classes for better error handling:
268
+
269
+ ```typescript
270
+ import {
271
+ TokenProviderError,
272
+ ValidationError,
273
+ RefreshError,
274
+ SessionDataError,
275
+ ServiceKeyError,
276
+ BrowserAuthError,
277
+ } from '@mcp-abap-adt/auth-providers';
278
+
279
+ try {
280
+ const result = await provider.refreshTokenFromSession(authConfig);
281
+ } catch (error) {
282
+ if (error instanceof ValidationError) {
283
+ // authConfig validation failed
284
+ console.error('Missing required fields:', error.missingFields);
285
+ console.error('Error code:', error.code); // 'VALIDATION_ERROR'
286
+ } else if (error instanceof RefreshError) {
287
+ // Token refresh operation failed
288
+ console.error('Refresh failed:', error.message);
289
+ console.error('Original error:', error.cause);
290
+ console.error('Error code:', error.code); // 'REFRESH_ERROR'
291
+ } else if (error instanceof BrowserAuthError) {
292
+ // Browser authentication failed
293
+ console.error('Browser auth failed:', error.cause);
294
+ }
295
+ }
296
+ ```
297
+
298
+ **Error Types**:
299
+ - `TokenProviderError` - Base class with `code: string` property
300
+ - `ValidationError` - authConfig validation failed, includes `missingFields: string[]`
301
+ - `RefreshError` - Token refresh failed, includes `cause?: Error`
302
+ - `SessionDataError` - Session data invalid, includes `missingFields: string[]`
303
+ - `ServiceKeyError` - Service key data invalid, includes `missingFields: string[]`
304
+ - `BrowserAuthError` - Browser auth failed, includes `cause?: Error`
305
+
306
+ All error codes are defined in `@mcp-abap-adt/interfaces` package as `TOKEN_PROVIDER_ERROR_CODES`.
307
+
210
308
  ## Testing
211
309
 
212
310
  The package includes both unit tests (with mocks) and integration tests (with real files and services).
@@ -272,10 +370,7 @@ Example output:
272
370
 
273
371
  ## Dependencies
274
372
 
275
- - `@mcp-abap-adt/auth-broker` (^0.1.6) - Interface definitions
276
- - `@mcp-abap-adt/auth-stores` (^0.1.2) - Store implementations
277
- - `@mcp-abap-adt/connection` (^0.1.13) - Connection utilities
278
- - `@mcp-abap-adt/logger` (^0.1.0) - Logging utilities
373
+ - `@mcp-abap-adt/interfaces` (^0.2.2) - Interface definitions and error code constants
279
374
  - `axios` - HTTP client
280
375
  - `express` - OAuth2 callback server
281
376
  - `open` - Browser opening utility
@@ -0,0 +1,49 @@
1
+ /**
2
+ * Token Provider Error Types
3
+ *
4
+ * Defines specific error types that token providers can throw
5
+ * to enable better error handling and debugging.
6
+ */
7
+ /**
8
+ * Base class for all token provider errors
9
+ */
10
+ export declare class TokenProviderError extends Error {
11
+ readonly code: string;
12
+ constructor(message: string, code: string);
13
+ }
14
+ /**
15
+ * Thrown when authentication configuration is invalid or incomplete
16
+ */
17
+ export declare class ValidationError extends TokenProviderError {
18
+ readonly missingFields?: string[] | undefined;
19
+ constructor(message: string, missingFields?: string[] | undefined);
20
+ }
21
+ /**
22
+ * Thrown when token refresh operation fails
23
+ */
24
+ export declare class RefreshError extends TokenProviderError {
25
+ readonly cause?: Error | undefined;
26
+ constructor(message: string, cause?: Error | undefined);
27
+ }
28
+ /**
29
+ * Thrown when session data is invalid or incomplete
30
+ */
31
+ export declare class SessionDataError extends TokenProviderError {
32
+ readonly missingFields?: string[] | undefined;
33
+ constructor(message: string, missingFields?: string[] | undefined);
34
+ }
35
+ /**
36
+ * Thrown when service key data is invalid or incomplete
37
+ */
38
+ export declare class ServiceKeyError extends TokenProviderError {
39
+ readonly missingFields?: string[] | undefined;
40
+ constructor(message: string, missingFields?: string[] | undefined);
41
+ }
42
+ /**
43
+ * Thrown when browser authentication fails or is cancelled
44
+ */
45
+ export declare class BrowserAuthError extends TokenProviderError {
46
+ readonly cause?: Error | undefined;
47
+ constructor(message: string, cause?: Error | undefined);
48
+ }
49
+ //# sourceMappingURL=TokenProviderErrors.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TokenProviderErrors.d.ts","sourceRoot":"","sources":["../../src/errors/TokenProviderErrors.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH;;GAEG;AACH,qBAAa,kBAAmB,SAAQ,KAAK;aACE,IAAI,EAAE,MAAM;gBAA7C,OAAO,EAAE,MAAM,EAAkB,IAAI,EAAE,MAAM;CAK1D;AAED;;GAEG;AACH,qBAAa,eAAgB,SAAQ,kBAAkB;aACR,aAAa,CAAC,EAAE,MAAM,EAAE;gBAAzD,OAAO,EAAE,MAAM,EAAkB,aAAa,CAAC,EAAE,MAAM,EAAE,YAAA;CAKtE;AAED;;GAEG;AACH,qBAAa,YAAa,SAAQ,kBAAkB;aACL,KAAK,CAAC,EAAE,KAAK;gBAA9C,OAAO,EAAE,MAAM,EAAkB,KAAK,CAAC,EAAE,KAAK,YAAA;CAK3D;AAED;;GAEG;AACH,qBAAa,gBAAiB,SAAQ,kBAAkB;aACT,aAAa,CAAC,EAAE,MAAM,EAAE;gBAAzD,OAAO,EAAE,MAAM,EAAkB,aAAa,CAAC,EAAE,MAAM,EAAE,YAAA;CAKtE;AAED;;GAEG;AACH,qBAAa,eAAgB,SAAQ,kBAAkB;aACR,aAAa,CAAC,EAAE,MAAM,EAAE;gBAAzD,OAAO,EAAE,MAAM,EAAkB,aAAa,CAAC,EAAE,MAAM,EAAE,YAAA;CAKtE;AAED;;GAEG;AACH,qBAAa,gBAAiB,SAAQ,kBAAkB;aACT,KAAK,CAAC,EAAE,KAAK;gBAA9C,OAAO,EAAE,MAAM,EAAkB,KAAK,CAAC,EAAE,KAAK,YAAA;CAK3D"}
@@ -0,0 +1,88 @@
1
+ "use strict";
2
+ /**
3
+ * Token Provider Error Types
4
+ *
5
+ * Defines specific error types that token providers can throw
6
+ * to enable better error handling and debugging.
7
+ */
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.BrowserAuthError = exports.ServiceKeyError = exports.SessionDataError = exports.RefreshError = exports.ValidationError = exports.TokenProviderError = void 0;
10
+ const interfaces_1 = require("@mcp-abap-adt/interfaces");
11
+ /**
12
+ * Base class for all token provider errors
13
+ */
14
+ class TokenProviderError extends Error {
15
+ code;
16
+ constructor(message, code) {
17
+ super(message);
18
+ this.code = code;
19
+ this.name = 'TokenProviderError';
20
+ Object.setPrototypeOf(this, TokenProviderError.prototype);
21
+ }
22
+ }
23
+ exports.TokenProviderError = TokenProviderError;
24
+ /**
25
+ * Thrown when authentication configuration is invalid or incomplete
26
+ */
27
+ class ValidationError extends TokenProviderError {
28
+ missingFields;
29
+ constructor(message, missingFields) {
30
+ super(message, interfaces_1.TOKEN_PROVIDER_ERROR_CODES.VALIDATION_ERROR);
31
+ this.missingFields = missingFields;
32
+ this.name = 'ValidationError';
33
+ Object.setPrototypeOf(this, ValidationError.prototype);
34
+ }
35
+ }
36
+ exports.ValidationError = ValidationError;
37
+ /**
38
+ * Thrown when token refresh operation fails
39
+ */
40
+ class RefreshError extends TokenProviderError {
41
+ cause;
42
+ constructor(message, cause) {
43
+ super(message, interfaces_1.TOKEN_PROVIDER_ERROR_CODES.REFRESH_ERROR);
44
+ this.cause = cause;
45
+ this.name = 'RefreshError';
46
+ Object.setPrototypeOf(this, RefreshError.prototype);
47
+ }
48
+ }
49
+ exports.RefreshError = RefreshError;
50
+ /**
51
+ * Thrown when session data is invalid or incomplete
52
+ */
53
+ class SessionDataError extends TokenProviderError {
54
+ missingFields;
55
+ constructor(message, missingFields) {
56
+ super(message, interfaces_1.TOKEN_PROVIDER_ERROR_CODES.SESSION_DATA_ERROR);
57
+ this.missingFields = missingFields;
58
+ this.name = 'SessionDataError';
59
+ Object.setPrototypeOf(this, SessionDataError.prototype);
60
+ }
61
+ }
62
+ exports.SessionDataError = SessionDataError;
63
+ /**
64
+ * Thrown when service key data is invalid or incomplete
65
+ */
66
+ class ServiceKeyError extends TokenProviderError {
67
+ missingFields;
68
+ constructor(message, missingFields) {
69
+ super(message, interfaces_1.TOKEN_PROVIDER_ERROR_CODES.SERVICE_KEY_ERROR);
70
+ this.missingFields = missingFields;
71
+ this.name = 'ServiceKeyError';
72
+ Object.setPrototypeOf(this, ServiceKeyError.prototype);
73
+ }
74
+ }
75
+ exports.ServiceKeyError = ServiceKeyError;
76
+ /**
77
+ * Thrown when browser authentication fails or is cancelled
78
+ */
79
+ class BrowserAuthError extends TokenProviderError {
80
+ cause;
81
+ constructor(message, cause) {
82
+ super(message, interfaces_1.TOKEN_PROVIDER_ERROR_CODES.BROWSER_AUTH_ERROR);
83
+ this.cause = cause;
84
+ this.name = 'BrowserAuthError';
85
+ Object.setPrototypeOf(this, BrowserAuthError.prototype);
86
+ }
87
+ }
88
+ exports.BrowserAuthError = BrowserAuthError;
package/dist/index.d.ts CHANGED
@@ -6,4 +6,5 @@
6
6
  */
7
7
  export { XsuaaTokenProvider } from './providers/XsuaaTokenProvider';
8
8
  export { BtpTokenProvider } from './providers/BtpTokenProvider';
9
+ export { TokenProviderError, ValidationError, RefreshError, SessionDataError, ServiceKeyError, BrowserAuthError, } from './errors/TokenProviderErrors';
9
10
  //# 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"}
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,EACL,kBAAkB,EAClB,eAAe,EACf,YAAY,EACZ,gBAAgB,EAChB,eAAe,EACf,gBAAgB,GACjB,MAAM,8BAA8B,CAAC"}
package/dist/index.js CHANGED
@@ -6,9 +6,17 @@
6
6
  * Provides XSUAA and BTP token providers
7
7
  */
8
8
  Object.defineProperty(exports, "__esModule", { value: true });
9
- exports.BtpTokenProvider = exports.XsuaaTokenProvider = void 0;
9
+ exports.BrowserAuthError = exports.ServiceKeyError = exports.SessionDataError = exports.RefreshError = exports.ValidationError = exports.TokenProviderError = 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
+ // Errors
16
+ var TokenProviderErrors_1 = require("./errors/TokenProviderErrors");
17
+ Object.defineProperty(exports, "TokenProviderError", { enumerable: true, get: function () { return TokenProviderErrors_1.TokenProviderError; } });
18
+ Object.defineProperty(exports, "ValidationError", { enumerable: true, get: function () { return TokenProviderErrors_1.ValidationError; } });
19
+ Object.defineProperty(exports, "RefreshError", { enumerable: true, get: function () { return TokenProviderErrors_1.RefreshError; } });
20
+ Object.defineProperty(exports, "SessionDataError", { enumerable: true, get: function () { return TokenProviderErrors_1.SessionDataError; } });
21
+ Object.defineProperty(exports, "ServiceKeyError", { enumerable: true, get: function () { return TokenProviderErrors_1.ServiceKeyError; } });
22
+ Object.defineProperty(exports, "BrowserAuthError", { enumerable: true, get: function () { return TokenProviderErrors_1.BrowserAuthError; } });
@@ -23,6 +23,8 @@ export declare class BtpTokenProvider implements ITokenProvider {
23
23
  */
24
24
  private refreshJwtToken;
25
25
  getConnectionConfig(authConfig: IAuthorizationConfig, options?: ITokenProviderOptions): Promise<ITokenProviderResult>;
26
+ refreshTokenFromSession(authConfig: IAuthorizationConfig, options?: ITokenProviderOptions): Promise<ITokenProviderResult>;
27
+ refreshTokenFromServiceKey(authConfig: IAuthorizationConfig, options?: ITokenProviderOptions): Promise<ITokenProviderResult>;
26
28
  validateToken(token: string, serviceUrl?: string): Promise<boolean>;
27
29
  }
28
30
  //# sourceMappingURL=BtpTokenProvider.d.ts.map
@@ -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,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"}
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;AAQ3I;;;;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,uBAAuB,CAC3B,UAAU,EAAE,oBAAoB,EAChC,OAAO,CAAC,EAAE,qBAAqB,GAC9B,OAAO,CAAC,oBAAoB,CAAC;IAuC1B,0BAA0B,CAC9B,UAAU,EAAE,oBAAoB,EAChC,OAAO,CAAC,EAAE,qBAAqB,GAC9B,OAAO,CAAC,oBAAoB,CAAC;IAuC1B,aAAa,CAAC,KAAK,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;CA0C1E"}
@@ -10,6 +10,7 @@ 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 TokenProviderErrors_1 = require("../errors/TokenProviderErrors");
13
14
  const axios_1 = __importDefault(require("axios"));
14
15
  // Import internal functions (not exported)
15
16
  const browserAuth_1 = require("../auth/browserAuth");
@@ -65,6 +66,68 @@ class BtpTokenProvider {
65
66
  refreshToken: result.refreshToken,
66
67
  };
67
68
  }
69
+ async refreshTokenFromSession(authConfig, options) {
70
+ const logger = options?.logger;
71
+ const browser = options?.browser || 'system';
72
+ // Validate authConfig
73
+ const missingFields = [];
74
+ if (!authConfig.uaaUrl)
75
+ missingFields.push('uaaUrl');
76
+ if (!authConfig.uaaClientId)
77
+ missingFields.push('uaaClientId');
78
+ if (!authConfig.uaaClientSecret)
79
+ missingFields.push('uaaClientSecret');
80
+ if (missingFields.length > 0) {
81
+ throw new TokenProviderErrors_1.ValidationError(`BTP refreshTokenFromSession: authConfig missing required fields: ${missingFields.join(', ')}`, missingFields);
82
+ }
83
+ if (logger) {
84
+ logger.debug('BTP: Refreshing token from session using browser authentication (UAA_URL)...');
85
+ }
86
+ // BTP refresh from session uses browser authentication through UAA_URL
87
+ try {
88
+ const result = await this.startBrowserAuth(authConfig, browser, logger);
89
+ return {
90
+ connectionConfig: {
91
+ authorizationToken: result.accessToken,
92
+ },
93
+ refreshToken: result.refreshToken,
94
+ };
95
+ }
96
+ catch (error) {
97
+ throw new TokenProviderErrors_1.RefreshError(`BTP refreshTokenFromSession failed: ${error.message}`, error);
98
+ }
99
+ }
100
+ async refreshTokenFromServiceKey(authConfig, options) {
101
+ const logger = options?.logger;
102
+ const browser = options?.browser || 'system';
103
+ // Validate authConfig
104
+ const missingFields = [];
105
+ if (!authConfig.uaaUrl)
106
+ missingFields.push('uaaUrl');
107
+ if (!authConfig.uaaClientId)
108
+ missingFields.push('uaaClientId');
109
+ if (!authConfig.uaaClientSecret)
110
+ missingFields.push('uaaClientSecret');
111
+ if (missingFields.length > 0) {
112
+ throw new TokenProviderErrors_1.ValidationError(`BTP refreshTokenFromServiceKey: authConfig missing required fields: ${missingFields.join(', ')}`, missingFields);
113
+ }
114
+ if (logger) {
115
+ logger.debug('BTP: Refreshing token from service key using browser authentication...');
116
+ }
117
+ // BTP refresh from service key uses browser authentication
118
+ try {
119
+ const result = await this.startBrowserAuth(authConfig, browser, logger);
120
+ return {
121
+ connectionConfig: {
122
+ authorizationToken: result.accessToken,
123
+ },
124
+ refreshToken: result.refreshToken,
125
+ };
126
+ }
127
+ catch (error) {
128
+ throw new TokenProviderErrors_1.RefreshError(`BTP refreshTokenFromServiceKey failed: ${error.message}`, error);
129
+ }
130
+ }
68
131
  async validateToken(token, serviceUrl) {
69
132
  if (!token || !serviceUrl) {
70
133
  return false;
@@ -16,6 +16,8 @@ export declare class XsuaaTokenProvider implements ITokenProvider {
16
16
  */
17
17
  private getTokenWithClientCredentials;
18
18
  getConnectionConfig(authConfig: IAuthorizationConfig, options?: ITokenProviderOptions): Promise<ITokenProviderResult>;
19
+ refreshTokenFromSession(authConfig: IAuthorizationConfig, options?: ITokenProviderOptions): Promise<ITokenProviderResult>;
20
+ refreshTokenFromServiceKey(authConfig: IAuthorizationConfig, options?: ITokenProviderOptions): Promise<ITokenProviderResult>;
19
21
  validateToken(token: string, serviceUrl?: string): Promise<boolean>;
20
22
  }
21
23
  //# sourceMappingURL=XsuaaTokenProvider.d.ts.map
@@ -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;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"}
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;AAOlI;;;;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,uBAAuB,CAC3B,UAAU,EAAE,oBAAoB,EAChC,OAAO,CAAC,EAAE,qBAAqB,GAC9B,OAAO,CAAC,oBAAoB,CAAC;IA2C1B,0BAA0B,CAC9B,UAAU,EAAE,oBAAoB,EAChC,OAAO,CAAC,EAAE,qBAAqB,GAC9B,OAAO,CAAC,oBAAoB,CAAC;IAwC1B,aAAa,CAAC,KAAK,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;CAgD1E"}
@@ -5,11 +5,45 @@
5
5
  * Uses client_credentials grant type to obtain tokens (no browser required).
6
6
  * For XSUAA service keys with reduced scope access.
7
7
  */
8
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
9
+ if (k2 === undefined) k2 = k;
10
+ var desc = Object.getOwnPropertyDescriptor(m, k);
11
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
12
+ desc = { enumerable: true, get: function() { return m[k]; } };
13
+ }
14
+ Object.defineProperty(o, k2, desc);
15
+ }) : (function(o, m, k, k2) {
16
+ if (k2 === undefined) k2 = k;
17
+ o[k2] = m[k];
18
+ }));
19
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
20
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
21
+ }) : function(o, v) {
22
+ o["default"] = v;
23
+ });
24
+ var __importStar = (this && this.__importStar) || (function () {
25
+ var ownKeys = function(o) {
26
+ ownKeys = Object.getOwnPropertyNames || function (o) {
27
+ var ar = [];
28
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
29
+ return ar;
30
+ };
31
+ return ownKeys(o);
32
+ };
33
+ return function (mod) {
34
+ if (mod && mod.__esModule) return mod;
35
+ var result = {};
36
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
37
+ __setModuleDefault(result, mod);
38
+ return result;
39
+ };
40
+ })();
8
41
  var __importDefault = (this && this.__importDefault) || function (mod) {
9
42
  return (mod && mod.__esModule) ? mod : { "default": mod };
10
43
  };
11
44
  Object.defineProperty(exports, "__esModule", { value: true });
12
45
  exports.XsuaaTokenProvider = void 0;
46
+ const TokenProviderErrors_1 = require("../errors/TokenProviderErrors");
13
47
  const axios_1 = __importDefault(require("axios"));
14
48
  // Import internal function (not exported)
15
49
  const clientCredentialsAuth_1 = require("../auth/clientCredentialsAuth");
@@ -42,6 +76,68 @@ class XsuaaTokenProvider {
42
76
  // XSUAA client_credentials doesn't provide refresh token
43
77
  };
44
78
  }
79
+ async refreshTokenFromSession(authConfig, options) {
80
+ const logger = options?.logger;
81
+ // Validate authConfig
82
+ const missingFields = [];
83
+ if (!authConfig.uaaUrl)
84
+ missingFields.push('uaaUrl');
85
+ if (!authConfig.uaaClientId)
86
+ missingFields.push('uaaClientId');
87
+ if (!authConfig.uaaClientSecret)
88
+ missingFields.push('uaaClientSecret');
89
+ if (missingFields.length > 0) {
90
+ throw new TokenProviderErrors_1.ValidationError(`XSUAA refreshTokenFromSession: authConfig missing required fields: ${missingFields.join(', ')}`, missingFields);
91
+ }
92
+ if (logger) {
93
+ logger.debug('XSUAA: Refreshing token from session using client_credentials...');
94
+ }
95
+ // XSUAA refresh from session uses client_credentials (clientId/clientSecret)
96
+ try {
97
+ const result = await this.getTokenWithClientCredentials(authConfig.uaaUrl, authConfig.uaaClientId, authConfig.uaaClientSecret);
98
+ return {
99
+ connectionConfig: {
100
+ authorizationToken: result.accessToken,
101
+ },
102
+ // XSUAA client_credentials doesn't provide refresh token
103
+ };
104
+ }
105
+ catch (error) {
106
+ throw new TokenProviderErrors_1.RefreshError(`XSUAA refreshTokenFromSession failed: ${error.message}`, error);
107
+ }
108
+ }
109
+ async refreshTokenFromServiceKey(authConfig, options) {
110
+ const logger = options?.logger;
111
+ const browser = options?.browser || 'system';
112
+ // Validate authConfig
113
+ const missingFields = [];
114
+ if (!authConfig.uaaUrl)
115
+ missingFields.push('uaaUrl');
116
+ if (!authConfig.uaaClientId)
117
+ missingFields.push('uaaClientId');
118
+ if (!authConfig.uaaClientSecret)
119
+ missingFields.push('uaaClientSecret');
120
+ if (missingFields.length > 0) {
121
+ throw new TokenProviderErrors_1.ValidationError(`XSUAA refreshTokenFromServiceKey: authConfig missing required fields: ${missingFields.join(', ')}`, missingFields);
122
+ }
123
+ if (logger) {
124
+ logger.debug('XSUAA: Refreshing token from service key using browser authentication...');
125
+ }
126
+ // XSUAA refresh from service key uses browser authentication
127
+ try {
128
+ const { startBrowserAuth } = await Promise.resolve().then(() => __importStar(require('../auth/browserAuth')));
129
+ const result = await startBrowserAuth(authConfig, browser, logger);
130
+ return {
131
+ connectionConfig: {
132
+ authorizationToken: result.accessToken,
133
+ },
134
+ refreshToken: result.refreshToken,
135
+ };
136
+ }
137
+ catch (error) {
138
+ throw new TokenProviderErrors_1.RefreshError(`XSUAA refreshTokenFromServiceKey failed: ${error.message}`, error);
139
+ }
140
+ }
45
141
  async validateToken(token, serviceUrl) {
46
142
  // XSUAA tokens are validated by the service itself when making requests
47
143
  // If serviceUrl is provided, we can test the connection
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mcp-abap-adt/auth-providers",
3
- "version": "0.1.4",
3
+ "version": "0.2.0",
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",
@@ -48,7 +48,7 @@
48
48
  "node": ">=18.0.0"
49
49
  },
50
50
  "dependencies": {
51
- "@mcp-abap-adt/interfaces": "^0.1.1",
51
+ "@mcp-abap-adt/interfaces": "^0.2.2",
52
52
  "axios": "^1.11.0",
53
53
  "express": "^5.1.0",
54
54
  "open": "^11.0.0"