@mcp-abap-adt/auth-broker 0.2.11 → 0.2.12
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 +7 -0
- package/README.md +116 -108
- package/bin/generate-env-from-service-key.ts +26 -5
- package/bin/mcp-auth.ts +25 -94
- package/dist/AuthBroker.d.ts +3 -13
- package/dist/AuthBroker.d.ts.map +1 -1
- package/dist/AuthBroker.js +81 -239
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/providers/ITokenProvider.d.ts +3 -7
- package/dist/providers/ITokenProvider.d.ts.map +1 -1
- package/dist/providers/ITokenProvider.js +1 -4
- package/dist/providers/index.d.ts +1 -1
- package/dist/providers/index.d.ts.map +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -11,6 +11,13 @@ Thank you to all contributors! See [CONTRIBUTORS.md](CONTRIBUTORS.md) for the co
|
|
|
11
11
|
|
|
12
12
|
## [Unreleased]
|
|
13
13
|
|
|
14
|
+
## [0.2.12] - 2025-12-25
|
|
15
|
+
|
|
16
|
+
### Changed
|
|
17
|
+
- **Auth flow**: Broker now relies on `ITokenProvider.getTokens()` with no parameters and expects providers to manage refresh/re-auth internally.
|
|
18
|
+
- **Constructor**: `tokenProvider` is required and `allowBrowserAuth` is supported for non-interactive flows.
|
|
19
|
+
- **Docs**: Updated usage/architecture/export docs to reflect provider injection, new flow, and CLI usage.
|
|
20
|
+
|
|
14
21
|
## [0.2.11] - 2025-12-23
|
|
15
22
|
|
|
16
23
|
### Changed
|
package/README.md
CHANGED
|
@@ -7,7 +7,7 @@ JWT authentication broker for MCP ABAP ADT server. Manages authentication tokens
|
|
|
7
7
|
- 🔐 **Destination-based Authentication**: Load tokens based on `x-mcp-destination` header
|
|
8
8
|
- 📁 **Environment File Support**: Automatically loads tokens from `{destination}.env` files
|
|
9
9
|
- 🔄 **Automatic Token Refresh**: Refreshes expired tokens using service keys from `{destination}.json` files
|
|
10
|
-
- ✅ **Token Validation**: Validates tokens
|
|
10
|
+
- ✅ **Token Validation**: Validates tokens via provider (if `validateToken` is implemented)
|
|
11
11
|
- 💾 **Token Caching**: In-memory caching for improved performance
|
|
12
12
|
- 🔧 **Configurable Base Path**: Customize where `.env` and `.json` files are stored
|
|
13
13
|
|
|
@@ -19,19 +19,26 @@ npm install @mcp-abap-adt/auth-broker
|
|
|
19
19
|
|
|
20
20
|
## Usage
|
|
21
21
|
|
|
22
|
-
### Basic Usage (
|
|
22
|
+
### Basic Usage (Provider Required)
|
|
23
23
|
|
|
24
|
-
|
|
24
|
+
AuthBroker requires a token provider configured for the destination:
|
|
25
25
|
|
|
26
26
|
```typescript
|
|
27
27
|
import { AuthBroker, AbapSessionStore } from '@mcp-abap-adt/auth-broker';
|
|
28
|
+
import { AuthorizationCodeProvider } from '@mcp-abap-adt/auth-providers';
|
|
29
|
+
|
|
30
|
+
const tokenProvider = new AuthorizationCodeProvider({
|
|
31
|
+
uaaUrl: 'https://...authentication...hana.ondemand.com',
|
|
32
|
+
clientId: '...',
|
|
33
|
+
clientSecret: '...',
|
|
34
|
+
browser: 'system',
|
|
35
|
+
});
|
|
28
36
|
|
|
29
|
-
// Session-only mode - works if session has UAA credentials
|
|
30
37
|
const broker = new AuthBroker({
|
|
31
38
|
sessionStore: new AbapSessionStore('/path/to/destinations'),
|
|
39
|
+
tokenProvider,
|
|
32
40
|
});
|
|
33
41
|
|
|
34
|
-
// Get token - uses direct UAA HTTP requests automatically
|
|
35
42
|
const token = await broker.getToken('TRIAL');
|
|
36
43
|
```
|
|
37
44
|
|
|
@@ -40,37 +47,52 @@ const token = await broker.getToken('TRIAL');
|
|
|
40
47
|
For maximum flexibility, provide all three dependencies:
|
|
41
48
|
|
|
42
49
|
```typescript
|
|
43
|
-
import {
|
|
44
|
-
AuthBroker,
|
|
45
|
-
AbapServiceKeyStore,
|
|
46
|
-
AbapSessionStore,
|
|
47
|
-
BtpTokenProvider
|
|
50
|
+
import {
|
|
51
|
+
AuthBroker,
|
|
52
|
+
AbapServiceKeyStore,
|
|
53
|
+
AbapSessionStore,
|
|
48
54
|
} from '@mcp-abap-adt/auth-broker';
|
|
55
|
+
import { AuthorizationCodeProvider } from '@mcp-abap-adt/auth-providers';
|
|
49
56
|
|
|
50
57
|
const broker = new AuthBroker({
|
|
51
58
|
sessionStore: new AbapSessionStore('/path/to/destinations'),
|
|
52
59
|
serviceKeyStore: new AbapServiceKeyStore('/path/to/destinations'), // optional
|
|
53
|
-
tokenProvider: new
|
|
60
|
+
tokenProvider: new AuthorizationCodeProvider({
|
|
61
|
+
uaaUrl: 'https://...authentication...hana.ondemand.com',
|
|
62
|
+
clientId: '...',
|
|
63
|
+
clientSecret: '...',
|
|
64
|
+
browser: 'system',
|
|
65
|
+
}),
|
|
54
66
|
}, 'chrome', logger);
|
|
55
67
|
|
|
56
68
|
// Disable browser authentication for headless/stdio environments (e.g., MCP with Cline)
|
|
57
69
|
const brokerNoBrowser = new AuthBroker({
|
|
58
70
|
sessionStore: new AbapSessionStore('/path/to/destinations'),
|
|
59
71
|
serviceKeyStore: new AbapServiceKeyStore('/path/to/destinations'),
|
|
60
|
-
tokenProvider: new
|
|
72
|
+
tokenProvider: new AuthorizationCodeProvider({
|
|
73
|
+
uaaUrl: 'https://...authentication...hana.ondemand.com',
|
|
74
|
+
clientId: '...',
|
|
75
|
+
clientSecret: '...',
|
|
76
|
+
browser: 'none',
|
|
77
|
+
}),
|
|
61
78
|
allowBrowserAuth: false, // Throws BROWSER_AUTH_REQUIRED if browser auth needed
|
|
62
79
|
}, 'chrome', logger);
|
|
63
80
|
```
|
|
64
81
|
|
|
65
82
|
### Session + Service Key (For Initialization)
|
|
66
83
|
|
|
67
|
-
If you need to initialize sessions from service keys:
|
|
84
|
+
If you need to initialize sessions from service keys, create the provider from service key auth config:
|
|
68
85
|
|
|
69
86
|
```typescript
|
|
70
87
|
const broker = new AuthBroker({
|
|
71
88
|
sessionStore: new AbapSessionStore('/path/to/destinations'),
|
|
72
89
|
serviceKeyStore: new AbapServiceKeyStore('/path/to/destinations'),
|
|
73
|
-
|
|
90
|
+
tokenProvider: new AuthorizationCodeProvider({
|
|
91
|
+
uaaUrl: 'https://...authentication...hana.ondemand.com',
|
|
92
|
+
clientId: '...',
|
|
93
|
+
clientSecret: '...',
|
|
94
|
+
browser: 'system',
|
|
95
|
+
}),
|
|
74
96
|
});
|
|
75
97
|
```
|
|
76
98
|
|
|
@@ -94,16 +116,19 @@ To avoid port conflicts with browser authentication:
|
|
|
94
116
|
const broker = new AuthBroker({
|
|
95
117
|
sessionStore: new AbapSessionStore('/path/to/destinations'),
|
|
96
118
|
serviceKeyStore: new AbapServiceKeyStore('/path/to/destinations'),
|
|
97
|
-
tokenProvider: new
|
|
119
|
+
tokenProvider: new AuthorizationCodeProvider({
|
|
120
|
+
uaaUrl: 'https://...authentication...hana.ondemand.com',
|
|
121
|
+
clientId: '...',
|
|
122
|
+
clientSecret: '...',
|
|
123
|
+
browser: 'system',
|
|
124
|
+
redirectPort: 4001,
|
|
125
|
+
}),
|
|
98
126
|
}, 'chrome');
|
|
99
127
|
```
|
|
100
128
|
|
|
101
|
-
**Note**: The `BtpTokenProvider` automatically finds an available port if the requested port is in use. This prevents `EADDRINUSE` errors when multiple stdio servers run simultaneously. The server properly closes all connections and frees the port after authentication completes, ensuring no lingering port occupation.
|
|
102
|
-
|
|
103
129
|
### Getting Tokens
|
|
104
130
|
|
|
105
131
|
```typescript
|
|
106
|
-
// Get token - automatically uses direct UAA requests if UAA credentials available
|
|
107
132
|
const token = await broker.getToken('TRIAL');
|
|
108
133
|
|
|
109
134
|
// Force refresh token
|
|
@@ -282,7 +307,7 @@ This package supports two types of BTP authentication:
|
|
|
282
307
|
**Interface-Only Communication**: This package follows a fundamental development principle: **all interactions with external dependencies happen ONLY through interfaces**. The code knows **NOTHING beyond what is defined in the interfaces**.
|
|
283
308
|
|
|
284
309
|
This means:
|
|
285
|
-
- Does not know about concrete implementation classes (e.g., `AbapSessionStore`, `
|
|
310
|
+
- Does not know about concrete implementation classes (e.g., `AbapSessionStore`, `AuthorizationCodeProvider`)
|
|
286
311
|
- Does not know about internal data structures or methods not defined in interfaces
|
|
287
312
|
- Does not make assumptions about implementation behavior beyond interface contracts
|
|
288
313
|
- Does not access properties or methods not explicitly defined in interfaces
|
|
@@ -302,13 +327,11 @@ The `@mcp-abap-adt/auth-broker` package defines **interfaces** and provides **or
|
|
|
302
327
|
- **Orchestrates authentication flows**: Coordinates token retrieval, validation, and refresh using provided stores and providers
|
|
303
328
|
- **Manages token lifecycle**: Handles token caching, validation, and automatic refresh
|
|
304
329
|
- **Works with interfaces only**: Uses `IServiceKeyStore`, `ISessionStore`, and `ITokenProvider` interfaces without knowing concrete implementations
|
|
305
|
-
- **Delegates to providers**: Calls `tokenProvider.
|
|
306
|
-
- **Delegates to stores**:
|
|
330
|
+
- **Delegates to providers**: Calls `tokenProvider.getTokens()` to obtain tokens
|
|
331
|
+
- **Delegates to stores**: Saves tokens and connection configuration to `sessionStore`
|
|
307
332
|
|
|
308
333
|
#### What AuthBroker Does NOT Do
|
|
309
334
|
|
|
310
|
-
- **Does NOT know about `serviceUrl`**: `AuthBroker` does not know whether a specific `ISessionStore` implementation requires `serviceUrl` or not. It simply passes the `IConnectionConfig` returned by `tokenProvider` to `sessionStore.setConnectionConfig()`
|
|
311
|
-
- **Does NOT merge configurations**: `AuthBroker` does not merge `serviceUrl` from service keys with connection config from token providers. This is the responsibility of the consumer or the session store implementation
|
|
312
335
|
- **Does NOT implement storage**: File I/O, parsing, and storage logic are handled by concrete store implementations from `@mcp-abap-adt/auth-stores`
|
|
313
336
|
- **Does NOT implement token acquisition**: OAuth2 flows, refresh token logic, and client credentials are handled by concrete provider implementations from `@mcp-abap-adt/auth-providers`
|
|
314
337
|
|
|
@@ -317,9 +340,9 @@ The `@mcp-abap-adt/auth-broker` package defines **interfaces** and provides **or
|
|
|
317
340
|
The **consumer** (application using `AuthBroker`) is responsible for:
|
|
318
341
|
|
|
319
342
|
1. **Selecting appropriate implementations**: Choose the correct `IServiceKeyStore`, `ISessionStore`, and `ITokenProvider` implementations based on the use case:
|
|
320
|
-
- **ABAP systems**: Use `AbapServiceKeyStore`, `AbapSessionStore` (or `SafeAbapSessionStore`), and `
|
|
321
|
-
- **BTP systems**: Use `AbapServiceKeyStore`, `BtpSessionStore` (or `SafeBtpSessionStore`), and `
|
|
322
|
-
- **XSUAA services**: Use `XsuaaServiceKeyStore`, `XsuaaSessionStore` (or `SafeXsuaaSessionStore`), and `
|
|
343
|
+
- **ABAP systems**: Use `AbapServiceKeyStore`, `AbapSessionStore` (or `SafeAbapSessionStore`), and `AuthorizationCodeProvider`
|
|
344
|
+
- **BTP systems**: Use `AbapServiceKeyStore`, `BtpSessionStore` (or `SafeBtpSessionStore`), and `AuthorizationCodeProvider`
|
|
345
|
+
- **XSUAA services**: Use `XsuaaServiceKeyStore`, `XsuaaSessionStore` (or `SafeXsuaaSessionStore`), and `ClientCredentialsProvider`
|
|
323
346
|
|
|
324
347
|
2. **Ensuring complete configuration**: If a session store requires `serviceUrl` (e.g., `AbapSessionStore` requires `sapUrl`), the consumer must ensure that:
|
|
325
348
|
- The session is created with `serviceUrl` before calling `AuthBroker.getToken()`, OR
|
|
@@ -346,8 +369,7 @@ Concrete `ISessionStore` implementations are responsible for:
|
|
|
346
369
|
Concrete `ITokenProvider` implementations are responsible for:
|
|
347
370
|
|
|
348
371
|
- **Obtaining tokens**: Using OAuth2 flows, refresh tokens, or client credentials to obtain JWT tokens
|
|
349
|
-
- **
|
|
350
|
-
- **Not returning `serviceUrl` if unknown**: Providers like `BtpTokenProvider` may not return `serviceUrl` because they only handle token acquisition, not connection configuration
|
|
372
|
+
- **Managing token lifecycle**: Caching, validating, refreshing, and re-authenticating as needed
|
|
351
373
|
|
|
352
374
|
### Design Principles
|
|
353
375
|
|
|
@@ -361,22 +383,6 @@ Concrete `ITokenProvider` implementations are responsible for:
|
|
|
361
383
|
4. **Interface Segregation**: Interfaces are focused and minimal, containing only what's necessary for their specific purpose
|
|
362
384
|
5. **Open/Closed Principle**: New store and provider implementations can be added without modifying `AuthBroker`
|
|
363
385
|
|
|
364
|
-
### Example: Why AuthBroker Doesn't Handle `serviceUrl`
|
|
365
|
-
|
|
366
|
-
Consider this scenario:
|
|
367
|
-
- `BtpTokenProvider.getConnectionConfig()` returns `IConnectionConfig` with `authorizationToken` but **without** `serviceUrl` (because it only handles token acquisition)
|
|
368
|
-
- `AbapSessionStore.setConnectionConfig()` requires `sapUrl` (which maps to `serviceUrl`)
|
|
369
|
-
|
|
370
|
-
If `AuthBroker` tried to merge `serviceUrl` from `serviceKeyStore`, it would:
|
|
371
|
-
1. Violate the DIP by knowing about specific store requirements
|
|
372
|
-
2. Break the abstraction - `AuthBroker` shouldn't know that `AbapSessionStore` needs `serviceUrl`
|
|
373
|
-
3. Create coupling between `AuthBroker` and concrete implementations
|
|
374
|
-
|
|
375
|
-
Instead, the consumer or `AbapSessionStore` itself should handle this:
|
|
376
|
-
- **Option 1**: Consumer retrieves `serviceUrl` from `serviceKeyStore` and ensures it's in the session before calling `AuthBroker.getToken()`
|
|
377
|
-
- **Option 2**: `AbapSessionStore.setConnectionConfig()` retrieves `serviceUrl` from `serviceKeyStore` internally if not provided
|
|
378
|
-
- **Option 3**: `AbapSessionStore.setConnectionConfig()` uses existing `sapUrl` from current session if available
|
|
379
|
-
|
|
380
386
|
## API
|
|
381
387
|
|
|
382
388
|
### `AuthBroker`
|
|
@@ -388,7 +394,8 @@ new AuthBroker(
|
|
|
388
394
|
config: {
|
|
389
395
|
sessionStore: ISessionStore; // required
|
|
390
396
|
serviceKeyStore?: IServiceKeyStore; // optional
|
|
391
|
-
tokenProvider
|
|
397
|
+
tokenProvider: ITokenProvider; // required
|
|
398
|
+
allowBrowserAuth?: boolean; // optional
|
|
392
399
|
},
|
|
393
400
|
browser?: string,
|
|
394
401
|
logger?: ILogger
|
|
@@ -399,7 +406,8 @@ new AuthBroker(
|
|
|
399
406
|
- `config` - Configuration object:
|
|
400
407
|
- `sessionStore` - **Required** - Store for session data. Must contain initial session with `serviceUrl`
|
|
401
408
|
- `serviceKeyStore` - **Optional** - Store for service keys. Only needed for initializing sessions from service keys
|
|
402
|
-
- `tokenProvider` - **
|
|
409
|
+
- `tokenProvider` - **Required** - Token provider for token acquisition and refresh
|
|
410
|
+
- `allowBrowserAuth` - **Optional** - When `false`, throws `BROWSER_AUTH_REQUIRED` instead of launching browser auth
|
|
403
411
|
- `browser` - Optional browser name for authentication (`chrome`, `edge`, `firefox`, `system`, `headless`, `none`). Default: `system`
|
|
404
412
|
- Use `'headless'` for SSH/remote sessions - logs URL and waits for manual callback
|
|
405
413
|
- Use `'none'` for automated tests - logs URL and rejects immediately
|
|
@@ -411,16 +419,15 @@ new AuthBroker(
|
|
|
411
419
|
- **`sessionStore` (required)**: Always required. Must contain initial session with `serviceUrl`
|
|
412
420
|
- **`serviceKeyStore` (optional)**:
|
|
413
421
|
- Required if you need to initialize sessions from service keys (Step 0)
|
|
414
|
-
- Not needed if session already contains
|
|
415
|
-
- **`tokenProvider` (
|
|
416
|
-
-
|
|
417
|
-
-
|
|
418
|
-
- Not needed if session contains valid UAA credentials (direct UAA HTTP requests will be used)
|
|
422
|
+
- Not needed if session already contains authorization config and tokens
|
|
423
|
+
- **`tokenProvider` (required)**:
|
|
424
|
+
- Used for all token acquisition and refresh flows
|
|
425
|
+
- Must be configured with the destination's auth parameters (e.g., UAA credentials)
|
|
419
426
|
|
|
420
427
|
**Available Implementations:**
|
|
421
|
-
- **ABAP**: `AbapServiceKeyStore(directory, defaultServiceUrl?, logger?)`, `AbapSessionStore(directory, defaultServiceUrl?, logger?)`, `SafeAbapSessionStore(defaultServiceUrl?, logger?)`, `
|
|
422
|
-
- **XSUAA** (reduced scope): `XsuaaServiceKeyStore(directory, logger?)`, `XsuaaSessionStore(directory, defaultServiceUrl, logger?)`, `SafeXsuaaSessionStore(defaultServiceUrl, logger?)`, `
|
|
423
|
-
- **BTP** (full scope for ABAP): `AbapServiceKeyStore(directory, defaultServiceUrl?, logger?)`, `BtpSessionStore(directory, defaultServiceUrl, logger?)`, `SafeBtpSessionStore(defaultServiceUrl, logger?)`, `
|
|
428
|
+
- **ABAP**: `AbapServiceKeyStore(directory, defaultServiceUrl?, logger?)`, `AbapSessionStore(directory, defaultServiceUrl?, logger?)`, `SafeAbapSessionStore(defaultServiceUrl?, logger?)`, `AuthorizationCodeProvider(...)`
|
|
429
|
+
- **XSUAA** (reduced scope): `XsuaaServiceKeyStore(directory, logger?)`, `XsuaaSessionStore(directory, defaultServiceUrl, logger?)`, `SafeXsuaaSessionStore(defaultServiceUrl, logger?)`, `ClientCredentialsProvider(...)`
|
|
430
|
+
- **BTP** (full scope for ABAP): `AbapServiceKeyStore(directory, defaultServiceUrl?, logger?)`, `BtpSessionStore(directory, defaultServiceUrl, logger?)`, `SafeBtpSessionStore(defaultServiceUrl, logger?)`, `AuthorizationCodeProvider(...)`
|
|
424
431
|
|
|
425
432
|
#### Methods
|
|
426
433
|
|
|
@@ -429,31 +436,34 @@ new AuthBroker(
|
|
|
429
436
|
Gets authentication token for destination. Implements a three-step flow:
|
|
430
437
|
|
|
431
438
|
**Step 0: Initialize Session with Token (if needed)**
|
|
432
|
-
- Checks if session has `authorizationToken` and
|
|
433
|
-
- If both are
|
|
434
|
-
-
|
|
435
|
-
-
|
|
436
|
-
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
- If
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
- If successful → returns new token
|
|
439
|
+
- Checks if session has `authorizationToken` and authorization config
|
|
440
|
+
- If both are missing and `serviceKeyStore` is available:
|
|
441
|
+
- Loads authorization config from service key
|
|
442
|
+
- Uses `tokenProvider.getTokens()` to obtain tokens
|
|
443
|
+
- Persists tokens to session
|
|
444
|
+
- Otherwise → proceeds to Step 1
|
|
445
|
+
|
|
446
|
+
**Step 1: Token Validation**
|
|
447
|
+
- If token exists in session and provider supports `validateToken`, validate it
|
|
448
|
+
- If valid → returns token
|
|
449
|
+
- If provider does not support validation → returns token as-is
|
|
444
450
|
- Otherwise → proceeds to Step 2
|
|
445
451
|
|
|
446
|
-
**Step 2:
|
|
447
|
-
-
|
|
448
|
-
-
|
|
449
|
-
-
|
|
450
|
-
-
|
|
452
|
+
**Step 2: Token Refresh / Re-Auth**
|
|
453
|
+
- If session has authorization config:
|
|
454
|
+
- Uses `tokenProvider.getTokens()` to refresh or re-authenticate
|
|
455
|
+
- Persists tokens to session
|
|
456
|
+
- Returns new token
|
|
457
|
+
- If that fails (or no session auth config) and `serviceKeyStore` is available:
|
|
458
|
+
- Loads authorization config from service key
|
|
459
|
+
- Uses `tokenProvider.getTokens()` to obtain tokens
|
|
460
|
+
- Persists tokens to session
|
|
451
461
|
- If all failed → throws error
|
|
452
462
|
|
|
453
463
|
**Important Notes:**
|
|
454
|
-
-
|
|
455
|
-
- `tokenProvider` is
|
|
456
|
-
- Token validation is performed only when checking existing session. Tokens obtained through refresh
|
|
464
|
+
- All authentication is handled by the injected provider (authorization_code or client_credentials).
|
|
465
|
+
- `tokenProvider` is required for all token acquisition and refresh flows.
|
|
466
|
+
- Token validation is performed only when checking existing session. Tokens obtained through refresh are not validated before being saved.
|
|
457
467
|
- **Store errors are handled gracefully**: If service key files are missing or malformed, the broker logs the error and continues with fallback mechanisms (session store data or provider-based auth)
|
|
458
468
|
|
|
459
469
|
##### Error Handling
|
|
@@ -512,13 +522,7 @@ Example error scenarios handled:
|
|
|
512
522
|
|
|
513
523
|
##### `refreshToken(destination: string): Promise<string>`
|
|
514
524
|
|
|
515
|
-
Force refresh token for destination.
|
|
516
|
-
|
|
517
|
-
**Flow:**
|
|
518
|
-
- If refresh token exists and UAA credentials available → tries direct UAA refresh
|
|
519
|
-
- If direct UAA fails and `tokenProvider` available → uses provider
|
|
520
|
-
- If no refresh token but UAA credentials available → tries direct UAA client_credentials
|
|
521
|
-
- If all failed → throws error
|
|
525
|
+
Force refresh token for destination. Calls `getToken()` to run the full refresh flow and persist updated tokens.
|
|
522
526
|
|
|
523
527
|
##### `clearCache(destination: string): void`
|
|
524
528
|
|
|
@@ -530,14 +534,14 @@ Clear all cached tokens.
|
|
|
530
534
|
|
|
531
535
|
### Token Providers
|
|
532
536
|
|
|
533
|
-
The package uses `ITokenProvider` interface for token acquisition.
|
|
537
|
+
The package uses the `ITokenProvider` interface for token acquisition. Provider implementations live in `@mcp-abap-adt/auth-providers`:
|
|
534
538
|
|
|
535
|
-
- **`
|
|
539
|
+
- **`ClientCredentialsProvider`** - For XSUAA authentication (reduced scope)
|
|
536
540
|
- Uses client_credentials grant type
|
|
537
541
|
- No browser interaction required
|
|
538
542
|
- No refresh token provided
|
|
539
543
|
|
|
540
|
-
- **`
|
|
544
|
+
- **`AuthorizationCodeProvider`** - For BTP/ABAP authentication (full scope)
|
|
541
545
|
- Constructor accepts optional `browserAuthPort?: number` parameter (default: 3001)
|
|
542
546
|
- Automatically finds an available port if the requested port is in use (prevents `EADDRINUSE` errors)
|
|
543
547
|
- Server properly closes all connections and frees the port after authentication completes
|
|
@@ -553,55 +557,59 @@ import {
|
|
|
553
557
|
AuthBroker,
|
|
554
558
|
XsuaaServiceKeyStore,
|
|
555
559
|
XsuaaSessionStore,
|
|
556
|
-
XsuaaTokenProvider,
|
|
557
|
-
BtpTokenProvider,
|
|
558
560
|
AbapServiceKeyStore,
|
|
559
561
|
BtpSessionStore
|
|
560
562
|
} from '@mcp-abap-adt/auth-broker';
|
|
563
|
+
import {
|
|
564
|
+
ClientCredentialsProvider,
|
|
565
|
+
AuthorizationCodeProvider,
|
|
566
|
+
} from '@mcp-abap-adt/auth-providers';
|
|
561
567
|
|
|
562
|
-
// XSUAA authentication
|
|
568
|
+
// XSUAA authentication
|
|
563
569
|
const xsuaaBroker = new AuthBroker({
|
|
564
570
|
sessionStore: new XsuaaSessionStore('/path/to/sessions', 'https://mcp.example.com'),
|
|
565
|
-
|
|
571
|
+
tokenProvider: new ClientCredentialsProvider({
|
|
572
|
+
uaaUrl: 'https://auth.example.com',
|
|
573
|
+
clientId: '...',
|
|
574
|
+
clientSecret: '...',
|
|
575
|
+
}),
|
|
566
576
|
});
|
|
567
577
|
|
|
568
578
|
// XSUAA authentication - with service key initialization
|
|
569
579
|
const xsuaaBrokerWithServiceKey = new AuthBroker({
|
|
570
580
|
sessionStore: new XsuaaSessionStore('/path/to/sessions', 'https://mcp.example.com'),
|
|
571
581
|
serviceKeyStore: new XsuaaServiceKeyStore('/path/to/keys'),
|
|
572
|
-
|
|
582
|
+
tokenProvider: new ClientCredentialsProvider({
|
|
583
|
+
uaaUrl: 'https://auth.example.com',
|
|
584
|
+
clientId: '...',
|
|
585
|
+
clientSecret: '...',
|
|
586
|
+
}),
|
|
573
587
|
}, 'none');
|
|
574
588
|
|
|
575
|
-
// BTP authentication
|
|
589
|
+
// BTP authentication
|
|
576
590
|
const btpBroker = new AuthBroker({
|
|
577
591
|
sessionStore: new BtpSessionStore('/path/to/sessions', 'https://abap.example.com'),
|
|
578
|
-
|
|
592
|
+
tokenProvider: new AuthorizationCodeProvider({
|
|
593
|
+
uaaUrl: 'https://auth.example.com',
|
|
594
|
+
clientId: '...',
|
|
595
|
+
clientSecret: '...',
|
|
596
|
+
browser: 'system',
|
|
597
|
+
}),
|
|
579
598
|
});
|
|
580
599
|
|
|
581
600
|
// BTP authentication - with service key and provider (for browser auth)
|
|
582
601
|
const btpBrokerFull = new AuthBroker({
|
|
583
602
|
sessionStore: new BtpSessionStore('/path/to/sessions', 'https://abap.example.com'),
|
|
584
603
|
serviceKeyStore: new AbapServiceKeyStore('/path/to/keys'),
|
|
585
|
-
tokenProvider: new
|
|
604
|
+
tokenProvider: new AuthorizationCodeProvider({
|
|
605
|
+
uaaUrl: 'https://auth.example.com',
|
|
606
|
+
clientId: '...',
|
|
607
|
+
clientSecret: '...',
|
|
608
|
+
browser: 'system',
|
|
609
|
+
}),
|
|
586
610
|
});
|
|
587
611
|
```
|
|
588
612
|
|
|
589
|
-
### Direct UAA HTTP Requests
|
|
590
|
-
|
|
591
|
-
When UAA credentials are available in session, `AuthBroker` automatically uses direct HTTP requests to UAA without requiring `tokenProvider`:
|
|
592
|
-
|
|
593
|
-
- **Refresh Token Grant**: Direct HTTP POST to `{uaaUrl}/oauth/token` with `grant_type=refresh_token`
|
|
594
|
-
- **Client Credentials Grant**: Direct HTTP POST to `{uaaUrl}/oauth/token` with `grant_type=client_credentials`
|
|
595
|
-
|
|
596
|
-
**Benefits:**
|
|
597
|
-
- No dependency on `tokenProvider` when session has UAA credentials
|
|
598
|
-
- Faster token refresh (no provider overhead)
|
|
599
|
-
- Simpler configuration (only `sessionStore` needed)
|
|
600
|
-
|
|
601
|
-
**Fallback to Provider:**
|
|
602
|
-
- If direct UAA request fails and `tokenProvider` is available, broker automatically falls back to provider
|
|
603
|
-
- Provider is useful for browser authentication or alternative authentication flows
|
|
604
|
-
|
|
605
613
|
### CLI: mcp-auth
|
|
606
614
|
|
|
607
615
|
Generate or refresh `.env`/JSON output using AuthBroker + stores:
|
|
@@ -16,8 +16,16 @@
|
|
|
16
16
|
import * as path from 'path';
|
|
17
17
|
import * as fs from 'fs';
|
|
18
18
|
import { AuthBroker } from '../src/AuthBroker';
|
|
19
|
-
import {
|
|
20
|
-
|
|
19
|
+
import {
|
|
20
|
+
AbapServiceKeyStore,
|
|
21
|
+
AbapSessionStore,
|
|
22
|
+
XsuaaServiceKeyStore,
|
|
23
|
+
XsuaaSessionStore,
|
|
24
|
+
} from '@mcp-abap-adt/auth-stores';
|
|
25
|
+
import {
|
|
26
|
+
AuthorizationCodeProvider,
|
|
27
|
+
ClientCredentialsProvider,
|
|
28
|
+
} from '@mcp-abap-adt/auth-providers';
|
|
21
29
|
|
|
22
30
|
async function main() {
|
|
23
31
|
const args = process.argv.slice(2);
|
|
@@ -65,10 +73,24 @@ async function main() {
|
|
|
65
73
|
? new XsuaaSessionStore(sessionDir)
|
|
66
74
|
: new AbapSessionStore(sessionDir);
|
|
67
75
|
|
|
76
|
+
const authConfig = await serviceKeyStore.getAuthorizationConfig(destination);
|
|
77
|
+
if (!authConfig) {
|
|
78
|
+
throw new Error(`Missing authorization config for ${destination}`);
|
|
79
|
+
}
|
|
80
|
+
|
|
68
81
|
// Create token provider
|
|
69
82
|
const tokenProvider = isXsuaa
|
|
70
|
-
? new
|
|
71
|
-
|
|
83
|
+
? new ClientCredentialsProvider({
|
|
84
|
+
uaaUrl: authConfig.uaaUrl,
|
|
85
|
+
clientId: authConfig.uaaClientId,
|
|
86
|
+
clientSecret: authConfig.uaaClientSecret,
|
|
87
|
+
})
|
|
88
|
+
: new AuthorizationCodeProvider({
|
|
89
|
+
uaaUrl: authConfig.uaaUrl,
|
|
90
|
+
clientId: authConfig.uaaClientId,
|
|
91
|
+
clientSecret: authConfig.uaaClientSecret,
|
|
92
|
+
browser: 'system',
|
|
93
|
+
});
|
|
72
94
|
|
|
73
95
|
// Create AuthBroker
|
|
74
96
|
// For ABAP, use 'system' browser (will open browser for auth)
|
|
@@ -124,4 +146,3 @@ main().catch((error) => {
|
|
|
124
146
|
console.error('Fatal error:', error);
|
|
125
147
|
process.exit(1);
|
|
126
148
|
});
|
|
127
|
-
|
package/bin/mcp-auth.ts
CHANGED
|
@@ -32,12 +32,6 @@ import {
|
|
|
32
32
|
AuthorizationCodeProvider,
|
|
33
33
|
ClientCredentialsProvider,
|
|
34
34
|
} from '@mcp-abap-adt/auth-providers';
|
|
35
|
-
import type {
|
|
36
|
-
IAuthorizationConfig,
|
|
37
|
-
ITokenProvider,
|
|
38
|
-
ITokenProviderOptions,
|
|
39
|
-
ITokenProviderResult,
|
|
40
|
-
} from '@mcp-abap-adt/interfaces';
|
|
41
35
|
import {
|
|
42
36
|
ABAP_CONNECTION_VARS,
|
|
43
37
|
ABAP_AUTHORIZATION_VARS,
|
|
@@ -241,86 +235,6 @@ function parseArgs(): McpAuthOptions | null {
|
|
|
241
235
|
};
|
|
242
236
|
}
|
|
243
237
|
|
|
244
|
-
type ProviderMode = 'authorization_code' | 'client_credentials';
|
|
245
|
-
|
|
246
|
-
class BrokerTokenProvider implements ITokenProvider {
|
|
247
|
-
private mode: ProviderMode;
|
|
248
|
-
private browser?: string;
|
|
249
|
-
private redirectPort?: number;
|
|
250
|
-
|
|
251
|
-
constructor(mode: ProviderMode, browser?: string, redirectPort?: number) {
|
|
252
|
-
this.mode = mode;
|
|
253
|
-
this.browser = browser;
|
|
254
|
-
this.redirectPort = redirectPort;
|
|
255
|
-
}
|
|
256
|
-
|
|
257
|
-
async getConnectionConfig(
|
|
258
|
-
authConfig: IAuthorizationConfig,
|
|
259
|
-
options?: ITokenProviderOptions,
|
|
260
|
-
): Promise<ITokenProviderResult> {
|
|
261
|
-
return this.getTokenResult(authConfig, options);
|
|
262
|
-
}
|
|
263
|
-
|
|
264
|
-
async refreshTokenFromSession(
|
|
265
|
-
authConfig: IAuthorizationConfig,
|
|
266
|
-
options?: ITokenProviderOptions,
|
|
267
|
-
): Promise<ITokenProviderResult> {
|
|
268
|
-
return this.getTokenResult(authConfig, options);
|
|
269
|
-
}
|
|
270
|
-
|
|
271
|
-
async refreshTokenFromServiceKey(
|
|
272
|
-
authConfig: IAuthorizationConfig,
|
|
273
|
-
options?: ITokenProviderOptions,
|
|
274
|
-
): Promise<ITokenProviderResult> {
|
|
275
|
-
return this.getTokenResult(authConfig, options);
|
|
276
|
-
}
|
|
277
|
-
|
|
278
|
-
private async getTokenResult(
|
|
279
|
-
authConfig: IAuthorizationConfig,
|
|
280
|
-
options?: ITokenProviderOptions,
|
|
281
|
-
): Promise<ITokenProviderResult> {
|
|
282
|
-
const uaaUrl = authConfig.uaaUrl;
|
|
283
|
-
const uaaClientId = authConfig.uaaClientId;
|
|
284
|
-
const uaaClientSecret = authConfig.uaaClientSecret;
|
|
285
|
-
|
|
286
|
-
if (!uaaUrl || !uaaClientId || !uaaClientSecret) {
|
|
287
|
-
throw new Error('Auth config missing required UAA credentials');
|
|
288
|
-
}
|
|
289
|
-
|
|
290
|
-
if (this.mode === 'client_credentials') {
|
|
291
|
-
const provider = new ClientCredentialsProvider({
|
|
292
|
-
uaaUrl,
|
|
293
|
-
clientId: uaaClientId,
|
|
294
|
-
clientSecret: uaaClientSecret,
|
|
295
|
-
});
|
|
296
|
-
const result = await provider.getTokens();
|
|
297
|
-
return {
|
|
298
|
-
connectionConfig: {
|
|
299
|
-
authorizationToken: result.authorizationToken,
|
|
300
|
-
},
|
|
301
|
-
refreshToken: result.refreshToken,
|
|
302
|
-
};
|
|
303
|
-
}
|
|
304
|
-
|
|
305
|
-
const browserValue = options?.browser ?? this.browser ?? 'system';
|
|
306
|
-
const provider = new AuthorizationCodeProvider({
|
|
307
|
-
uaaUrl,
|
|
308
|
-
clientId: uaaClientId,
|
|
309
|
-
clientSecret: uaaClientSecret,
|
|
310
|
-
refreshToken: authConfig.refreshToken,
|
|
311
|
-
browser: browserValue,
|
|
312
|
-
redirectPort: this.redirectPort,
|
|
313
|
-
});
|
|
314
|
-
const result = await provider.getTokens();
|
|
315
|
-
return {
|
|
316
|
-
connectionConfig: {
|
|
317
|
-
authorizationToken: result.authorizationToken,
|
|
318
|
-
},
|
|
319
|
-
refreshToken: result.refreshToken,
|
|
320
|
-
};
|
|
321
|
-
}
|
|
322
|
-
}
|
|
323
|
-
|
|
324
238
|
function writeEnvFile(
|
|
325
239
|
outputPath: string,
|
|
326
240
|
authType: 'abap' | 'xsuaa',
|
|
@@ -531,15 +445,32 @@ async function main() {
|
|
|
531
445
|
? new XsuaaSessionStore(tempSessionDir, brokerServiceUrl)
|
|
532
446
|
: new AbapSessionStore(tempSessionDir);
|
|
533
447
|
|
|
448
|
+
const sessionAuthConfig =
|
|
449
|
+
await sessionStore.getAuthorizationConfig(destination);
|
|
450
|
+
const serviceKeyAuthConfig =
|
|
451
|
+
serviceKeyStore?.getAuthorizationConfig
|
|
452
|
+
? await serviceKeyStore.getAuthorizationConfig(destination)
|
|
453
|
+
: null;
|
|
454
|
+
const authConfig = sessionAuthConfig || serviceKeyAuthConfig;
|
|
455
|
+
if (!authConfig) {
|
|
456
|
+
throw new Error(`Authorization config not found for ${destination}`);
|
|
457
|
+
}
|
|
458
|
+
|
|
534
459
|
const useBrowserAuth = options.browser !== undefined;
|
|
535
|
-
const
|
|
536
|
-
?
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
460
|
+
const tokenProvider = useBrowserAuth
|
|
461
|
+
? new AuthorizationCodeProvider({
|
|
462
|
+
uaaUrl: authConfig.uaaUrl,
|
|
463
|
+
clientId: authConfig.uaaClientId,
|
|
464
|
+
clientSecret: authConfig.uaaClientSecret,
|
|
465
|
+
refreshToken: authConfig.refreshToken,
|
|
466
|
+
browser: options.browser,
|
|
467
|
+
redirectPort: options.redirectPort,
|
|
468
|
+
})
|
|
469
|
+
: new ClientCredentialsProvider({
|
|
470
|
+
uaaUrl: authConfig.uaaUrl,
|
|
471
|
+
clientId: authConfig.uaaClientId,
|
|
472
|
+
clientSecret: authConfig.uaaClientSecret,
|
|
473
|
+
});
|
|
543
474
|
|
|
544
475
|
const broker = new AuthBroker(
|
|
545
476
|
{
|
package/dist/AuthBroker.d.ts
CHANGED
|
@@ -55,27 +55,17 @@ export declare class AuthBroker {
|
|
|
55
55
|
/**
|
|
56
56
|
* Get UAA credentials from session or service key
|
|
57
57
|
*/
|
|
58
|
-
private
|
|
58
|
+
private getAuthorizationConfigFromServiceKey;
|
|
59
59
|
/**
|
|
60
60
|
* Save token and config to session
|
|
61
61
|
*/
|
|
62
62
|
private saveTokenToSession;
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
*/
|
|
66
|
-
private initializeSessionFromServiceKey;
|
|
63
|
+
private requestTokens;
|
|
64
|
+
private persistTokenResult;
|
|
67
65
|
/**
|
|
68
66
|
* Validate existing token (Step 1)
|
|
69
67
|
*/
|
|
70
68
|
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;
|
|
79
69
|
/**
|
|
80
70
|
* Get authentication token for destination.
|
|
81
71
|
* 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,EACL,KAAK,OAAO,EACZ,KAAK,eAAe,
|
|
1
|
+
{"version":3,"file":"AuthBroker.d.ts","sourceRoot":"","sources":["../src/AuthBroker.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EACL,KAAK,OAAO,EACZ,KAAK,eAAe,EAGrB,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;IAkFxE;;OAEG;YACW,eAAe;IA0D7B;;OAEG;YACW,aAAa;IAoD3B;;OAEG;YACW,oCAAoC;IA4ClD;;OAEG;YACW,kBAAkB;YAkClB,aAAa;YA8Cb,kBAAkB;IAiChC;;OAEG;YACW,qBAAqB;IA8BnC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAuCG;IACG,QAAQ,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAqIpD;;;;;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
|
@@ -84,8 +84,8 @@ class AuthBroker {
|
|
|
84
84
|
throw new Error('AuthBroker: sessionStore.setConnectionConfig must be a function');
|
|
85
85
|
}
|
|
86
86
|
// Check tokenProvider methods (required)
|
|
87
|
-
if (typeof tokenProvider.
|
|
88
|
-
throw new Error('AuthBroker: tokenProvider.
|
|
87
|
+
if (typeof tokenProvider.getTokens !== 'function') {
|
|
88
|
+
throw new Error('AuthBroker: tokenProvider.getTokens must be a function');
|
|
89
89
|
}
|
|
90
90
|
// validateToken is optional, so we don't check it
|
|
91
91
|
// Check serviceKeyStore methods (if provided)
|
|
@@ -196,14 +196,9 @@ class AuthBroker {
|
|
|
196
196
|
/**
|
|
197
197
|
* Get UAA credentials from session or service key
|
|
198
198
|
*/
|
|
199
|
-
async
|
|
200
|
-
if (authConfig?.uaaUrl &&
|
|
201
|
-
authConfig?.uaaClientId &&
|
|
202
|
-
authConfig?.uaaClientSecret) {
|
|
203
|
-
return authConfig;
|
|
204
|
-
}
|
|
199
|
+
async getAuthorizationConfigFromServiceKey(destination) {
|
|
205
200
|
if (!this.serviceKeyStore) {
|
|
206
|
-
throw new Error(`
|
|
201
|
+
throw new Error(`Authorization config not found for ${destination}. Session has no auth config and serviceKeyStore is not available.`);
|
|
207
202
|
}
|
|
208
203
|
let serviceKeyAuthConfig = null;
|
|
209
204
|
try {
|
|
@@ -219,21 +214,17 @@ class AuthBroker {
|
|
|
219
214
|
this.logger?.warn(`Failed to parse service key for ${destination}: ${error.filePath || 'unknown path'} - ${getErrorMessage(error)}`);
|
|
220
215
|
}
|
|
221
216
|
else {
|
|
222
|
-
this.logger?.warn(`Failed to get
|
|
217
|
+
this.logger?.warn(`Failed to get authorization config from service key store for ${destination}: ${getErrorMessage(error)}`);
|
|
223
218
|
}
|
|
224
219
|
}
|
|
225
220
|
else {
|
|
226
|
-
this.logger?.warn(`Failed to get
|
|
221
|
+
this.logger?.warn(`Failed to get authorization config from service key store for ${destination}: ${getErrorMessage(error)}`);
|
|
227
222
|
}
|
|
228
223
|
}
|
|
229
|
-
|
|
230
|
-
|
|
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'}.`);
|
|
224
|
+
if (!serviceKeyAuthConfig) {
|
|
225
|
+
throw new Error(`Authorization config not found for ${destination}. Session has no auth config${this.serviceKeyStore ? ' and serviceKeyStore has no auth config' : ' and serviceKeyStore is not available'}.`);
|
|
235
226
|
}
|
|
236
|
-
return
|
|
227
|
+
return serviceKeyAuthConfig;
|
|
237
228
|
}
|
|
238
229
|
/**
|
|
239
230
|
* Save token and config to session
|
|
@@ -254,74 +245,51 @@ class AuthBroker {
|
|
|
254
245
|
throw new Error(`Failed to save authorization config for destination "${destination}": ${getErrorMessage(error)}`);
|
|
255
246
|
}
|
|
256
247
|
}
|
|
257
|
-
|
|
258
|
-
|
|
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
|
-
const getConnectionConfig = this.tokenProvider.getConnectionConfig;
|
|
280
|
-
if (!getConnectionConfig) {
|
|
281
|
-
throw new Error('AuthBroker: tokenProvider.getConnectionConfig is required');
|
|
282
|
-
}
|
|
283
|
-
let tokenResult;
|
|
248
|
+
async requestTokens(destination, sourceLabel) {
|
|
249
|
+
this.logger?.debug(`Requesting tokens for ${destination} via ${sourceLabel}`);
|
|
284
250
|
try {
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
}
|
|
251
|
+
const getTokens = this.tokenProvider.getTokens;
|
|
252
|
+
if (!getTokens) {
|
|
253
|
+
throw new Error('AuthBroker: tokenProvider.getTokens is required');
|
|
254
|
+
}
|
|
255
|
+
return await getTokens.call(this.tokenProvider);
|
|
289
256
|
}
|
|
290
257
|
catch (error) {
|
|
291
258
|
if (hasErrorCode(error)) {
|
|
292
259
|
if (error.code === 'VALIDATION_ERROR') {
|
|
293
|
-
throw new Error(`
|
|
260
|
+
throw new Error(`Token provider validation failed for ${destination}: missing ${error.missingFields?.join(', ') || 'required fields'}`);
|
|
294
261
|
}
|
|
295
|
-
|
|
296
|
-
throw new Error(`
|
|
262
|
+
if (error.code === 'BROWSER_AUTH_ERROR') {
|
|
263
|
+
throw new Error(`Token provider browser authentication failed for ${destination}: ${getErrorMessage(error)}`);
|
|
297
264
|
}
|
|
298
|
-
|
|
265
|
+
if (error.code === 'ECONNREFUSED' ||
|
|
299
266
|
error.code === 'ETIMEDOUT' ||
|
|
300
267
|
error.code === 'ENOTFOUND') {
|
|
301
|
-
throw new Error(`
|
|
268
|
+
throw new Error(`Token provider network error for ${destination}: ${error.code}`);
|
|
269
|
+
}
|
|
270
|
+
if (error.code === 'SERVICE_KEY_ERROR') {
|
|
271
|
+
throw new Error(`Token provider service key error for ${destination}: ${getErrorMessage(error)}`);
|
|
302
272
|
}
|
|
303
273
|
}
|
|
304
|
-
throw new Error(`
|
|
274
|
+
throw new Error(`Token provider error for ${destination}: ${getErrorMessage(error)}`);
|
|
305
275
|
}
|
|
306
|
-
|
|
276
|
+
}
|
|
277
|
+
async persistTokenResult(destination, serviceUrl, baseConnConfig, authConfig, tokenResult) {
|
|
278
|
+
const token = tokenResult.authorizationToken;
|
|
307
279
|
if (!token) {
|
|
308
280
|
throw new Error(`Token provider did not return authorization token for destination "${destination}"`);
|
|
309
281
|
}
|
|
310
|
-
const tokenLength = token.length;
|
|
311
|
-
this.logger?.info(`Step 0: Token initialized for ${destination}: token(${tokenLength} chars), hasRefreshToken(${!!tokenResult.refreshToken})`);
|
|
312
|
-
// Get serviceUrl from service key store if not in connectionConfig
|
|
313
|
-
const serviceKeyConnConfig = await this.serviceKeyStore.getConnectionConfig(destination);
|
|
314
282
|
const connectionConfigWithServiceUrl = {
|
|
315
|
-
...
|
|
316
|
-
serviceUrl
|
|
317
|
-
|
|
318
|
-
|
|
283
|
+
...baseConnConfig,
|
|
284
|
+
serviceUrl,
|
|
285
|
+
authorizationToken: token,
|
|
286
|
+
authType: 'jwt',
|
|
319
287
|
};
|
|
320
|
-
|
|
321
|
-
...
|
|
322
|
-
refreshToken: tokenResult.refreshToken
|
|
323
|
-
}
|
|
324
|
-
|
|
288
|
+
const authorizationConfig = {
|
|
289
|
+
...authConfig,
|
|
290
|
+
refreshToken: tokenResult.refreshToken ?? authConfig.refreshToken,
|
|
291
|
+
};
|
|
292
|
+
await this.saveTokenToSession(destination, connectionConfigWithServiceUrl, authorizationConfig);
|
|
325
293
|
}
|
|
326
294
|
/**
|
|
327
295
|
* Validate existing token (Step 1)
|
|
@@ -345,138 +313,6 @@ class AuthBroker {
|
|
|
345
313
|
return false;
|
|
346
314
|
}
|
|
347
315
|
}
|
|
348
|
-
/**
|
|
349
|
-
* Refresh token from session (Step 2a)
|
|
350
|
-
*/
|
|
351
|
-
async refreshTokenFromSession(destination, uaaCredentials, refreshToken, serviceUrl) {
|
|
352
|
-
this.logger?.debug(`Step 2a: Trying refreshTokenFromSession for ${destination}`);
|
|
353
|
-
const authConfigWithRefresh = { ...uaaCredentials, refreshToken };
|
|
354
|
-
const refreshTokenFromSession = this.tokenProvider.refreshTokenFromSession;
|
|
355
|
-
if (!refreshTokenFromSession) {
|
|
356
|
-
throw new Error('AuthBroker: tokenProvider.refreshTokenFromSession is required');
|
|
357
|
-
}
|
|
358
|
-
let tokenResult;
|
|
359
|
-
try {
|
|
360
|
-
tokenResult = await refreshTokenFromSession(authConfigWithRefresh, {
|
|
361
|
-
browser: this.browser,
|
|
362
|
-
logger: this.logger,
|
|
363
|
-
});
|
|
364
|
-
}
|
|
365
|
-
catch (error) {
|
|
366
|
-
if (hasErrorCode(error)) {
|
|
367
|
-
if (error.code === 'ECONNREFUSED' ||
|
|
368
|
-
error.code === 'ETIMEDOUT' ||
|
|
369
|
-
error.code === 'ENOTFOUND') {
|
|
370
|
-
this.logger?.debug(`Step 2a: Network error during refreshTokenFromSession for ${destination}: ${error.code}. Trying refreshTokenFromServiceKey`);
|
|
371
|
-
throw error; // Re-throw to trigger fallback to Step 2b
|
|
372
|
-
}
|
|
373
|
-
}
|
|
374
|
-
throw error; // Re-throw other errors
|
|
375
|
-
}
|
|
376
|
-
const token = tokenResult.connectionConfig.authorizationToken;
|
|
377
|
-
if (!token) {
|
|
378
|
-
throw new Error(`Token provider did not return authorization token for destination "${destination}"`);
|
|
379
|
-
}
|
|
380
|
-
const tokenLength = token.length;
|
|
381
|
-
this.logger?.info(`Step 2a: Token refreshed from session for ${destination}: token(${tokenLength} chars), hasRefreshToken(${!!tokenResult.refreshToken})`);
|
|
382
|
-
// Get serviceUrl from session or service key
|
|
383
|
-
let serviceKeyServiceUrl;
|
|
384
|
-
if (this.serviceKeyStore) {
|
|
385
|
-
try {
|
|
386
|
-
const serviceKeyConn = await this.serviceKeyStore.getConnectionConfig(destination);
|
|
387
|
-
serviceKeyServiceUrl = serviceKeyConn?.serviceUrl;
|
|
388
|
-
}
|
|
389
|
-
catch (error) {
|
|
390
|
-
this.logger?.debug(`Could not get serviceUrl from service key store: ${getErrorMessage(error)}`);
|
|
391
|
-
}
|
|
392
|
-
}
|
|
393
|
-
const finalServiceUrl = tokenResult.connectionConfig.serviceUrl ||
|
|
394
|
-
serviceUrl ||
|
|
395
|
-
serviceKeyServiceUrl;
|
|
396
|
-
const connectionConfigWithServiceUrl = {
|
|
397
|
-
...tokenResult.connectionConfig,
|
|
398
|
-
serviceUrl: finalServiceUrl,
|
|
399
|
-
};
|
|
400
|
-
const authorizationConfig = {
|
|
401
|
-
...uaaCredentials,
|
|
402
|
-
refreshToken: tokenResult.refreshToken || refreshToken,
|
|
403
|
-
};
|
|
404
|
-
await this.saveTokenToSession(destination, connectionConfigWithServiceUrl, authorizationConfig);
|
|
405
|
-
return token;
|
|
406
|
-
}
|
|
407
|
-
/**
|
|
408
|
-
* Refresh token from service key (Step 2b)
|
|
409
|
-
*/
|
|
410
|
-
async refreshTokenFromServiceKey(destination, uaaCredentials, serviceUrl) {
|
|
411
|
-
if (!this.allowBrowserAuth) {
|
|
412
|
-
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.`);
|
|
413
|
-
error.code = 'BROWSER_AUTH_REQUIRED';
|
|
414
|
-
error.destination = destination;
|
|
415
|
-
this.logger?.error(`Step 2b: Browser auth required but disabled for ${destination}`);
|
|
416
|
-
throw error;
|
|
417
|
-
}
|
|
418
|
-
this.logger?.debug(`Step 2b: Trying refreshTokenFromServiceKey for ${destination}`);
|
|
419
|
-
const refreshTokenFromServiceKey = this.tokenProvider.refreshTokenFromServiceKey;
|
|
420
|
-
if (!refreshTokenFromServiceKey) {
|
|
421
|
-
throw new Error('AuthBroker: tokenProvider.refreshTokenFromServiceKey is required');
|
|
422
|
-
}
|
|
423
|
-
let tokenResult;
|
|
424
|
-
try {
|
|
425
|
-
tokenResult = await refreshTokenFromServiceKey(uaaCredentials, {
|
|
426
|
-
browser: this.browser,
|
|
427
|
-
logger: this.logger,
|
|
428
|
-
});
|
|
429
|
-
}
|
|
430
|
-
catch (error) {
|
|
431
|
-
if (hasErrorCode(error)) {
|
|
432
|
-
if (error.code === 'VALIDATION_ERROR') {
|
|
433
|
-
throw new Error(`Token refresh failed: Missing required fields in authConfig - ${error.missingFields?.join(', ')}`);
|
|
434
|
-
}
|
|
435
|
-
else if (error.code === 'BROWSER_AUTH_ERROR') {
|
|
436
|
-
throw new Error(`Token refresh failed: Browser authentication failed or was cancelled - ${getErrorMessage(error)}`);
|
|
437
|
-
}
|
|
438
|
-
else if (error.code === 'ECONNREFUSED' ||
|
|
439
|
-
error.code === 'ETIMEDOUT' ||
|
|
440
|
-
error.code === 'ENOTFOUND') {
|
|
441
|
-
throw new Error(`Token refresh failed: Network error - ${error.code}: Cannot reach authentication server`);
|
|
442
|
-
}
|
|
443
|
-
else if (error.code === 'SERVICE_KEY_ERROR') {
|
|
444
|
-
throw new Error(`Token refresh failed: Service key not found or invalid for ${destination}`);
|
|
445
|
-
}
|
|
446
|
-
}
|
|
447
|
-
throw new Error(`Token refresh failed for ${destination}: ${getErrorMessage(error)}`);
|
|
448
|
-
}
|
|
449
|
-
const token = tokenResult.connectionConfig.authorizationToken;
|
|
450
|
-
if (!token) {
|
|
451
|
-
throw new Error(`Token provider did not return authorization token for destination "${destination}"`);
|
|
452
|
-
}
|
|
453
|
-
const tokenLength = token.length;
|
|
454
|
-
this.logger?.info(`Step 2b: Token refreshed from service key for ${destination}: token(${tokenLength} chars), hasRefreshToken(${!!tokenResult.refreshToken})`);
|
|
455
|
-
// Get serviceUrl from session or service key
|
|
456
|
-
let serviceKeyServiceUrl;
|
|
457
|
-
if (this.serviceKeyStore) {
|
|
458
|
-
try {
|
|
459
|
-
const serviceKeyConn = await this.serviceKeyStore.getConnectionConfig(destination);
|
|
460
|
-
serviceKeyServiceUrl = serviceKeyConn?.serviceUrl;
|
|
461
|
-
}
|
|
462
|
-
catch (error) {
|
|
463
|
-
this.logger?.debug(`Could not get serviceUrl from service key store: ${getErrorMessage(error)}`);
|
|
464
|
-
}
|
|
465
|
-
}
|
|
466
|
-
const finalServiceUrl = tokenResult.connectionConfig.serviceUrl ||
|
|
467
|
-
serviceUrl ||
|
|
468
|
-
serviceKeyServiceUrl;
|
|
469
|
-
const connectionConfigWithServiceUrl = {
|
|
470
|
-
...tokenResult.connectionConfig,
|
|
471
|
-
serviceUrl: finalServiceUrl,
|
|
472
|
-
};
|
|
473
|
-
const authorizationConfig = {
|
|
474
|
-
...uaaCredentials,
|
|
475
|
-
refreshToken: tokenResult.refreshToken || uaaCredentials.refreshToken,
|
|
476
|
-
};
|
|
477
|
-
await this.saveTokenToSession(destination, connectionConfigWithServiceUrl, authorizationConfig);
|
|
478
|
-
return token;
|
|
479
|
-
}
|
|
480
316
|
/**
|
|
481
317
|
* Get authentication token for destination.
|
|
482
318
|
* Uses tokenProvider for all authentication operations (browser-based authorization).
|
|
@@ -525,34 +361,21 @@ class AuthBroker {
|
|
|
525
361
|
const serviceUrl = await this.getServiceUrl(destination, connConfig);
|
|
526
362
|
// Check if we have token or UAA credentials
|
|
527
363
|
const hasToken = !!connConfig?.authorizationToken;
|
|
528
|
-
const
|
|
529
|
-
|
|
530
|
-
authConfig?.uaaClientSecret);
|
|
531
|
-
this.logger?.debug(`Session check for ${destination}: hasToken(${hasToken}), hasUaaCredentials(${hasUaaCredentials}), serviceUrl(${serviceUrl ? 'yes' : 'no'})`);
|
|
364
|
+
const hasAuthConfig = !!authConfig;
|
|
365
|
+
this.logger?.debug(`Session check for ${destination}: hasToken(${hasToken}), hasAuthConfig(${hasAuthConfig}), serviceUrl(${serviceUrl ? 'yes' : 'no'})`);
|
|
532
366
|
// Step 0: Initialize Session with Token (if needed)
|
|
533
|
-
if (!hasToken && !
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
if (hasErrorCode(error) && error.code === 'BROWSER_AUTH_REQUIRED') {
|
|
540
|
-
throw error;
|
|
541
|
-
}
|
|
542
|
-
// Handle typed store errors
|
|
543
|
-
if (hasErrorCode(error)) {
|
|
544
|
-
if (error.code === interfaces_1.STORE_ERROR_CODES.FILE_NOT_FOUND) {
|
|
545
|
-
throw new Error(`Cannot initialize session for destination "${destination}": service key file not found`);
|
|
546
|
-
}
|
|
547
|
-
else if (error.code === interfaces_1.STORE_ERROR_CODES.PARSE_ERROR) {
|
|
548
|
-
throw new Error(`Cannot initialize session for destination "${destination}": service key parsing failed - ${getErrorMessage(error)}`);
|
|
549
|
-
}
|
|
550
|
-
else if (error.code === interfaces_1.STORE_ERROR_CODES.INVALID_CONFIG) {
|
|
551
|
-
throw new Error(`Cannot initialize session for destination "${destination}": invalid service key - missing ${error.missingFields?.join(', ') || 'required fields'}`);
|
|
552
|
-
}
|
|
553
|
-
}
|
|
367
|
+
if (!hasToken && !hasAuthConfig) {
|
|
368
|
+
if (!this.allowBrowserAuth) {
|
|
369
|
+
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.`);
|
|
370
|
+
error.code = 'BROWSER_AUTH_REQUIRED';
|
|
371
|
+
error.destination = destination;
|
|
372
|
+
this.logger?.error(`Step 0: Browser auth required but disabled for ${destination}`);
|
|
554
373
|
throw error;
|
|
555
374
|
}
|
|
375
|
+
const serviceKeyAuthConfig = await this.getAuthorizationConfigFromServiceKey(destination);
|
|
376
|
+
const tokenResult = await this.requestTokens(destination, 'serviceKey');
|
|
377
|
+
await this.persistTokenResult(destination, serviceUrl, connConfig, serviceKeyAuthConfig, tokenResult);
|
|
378
|
+
return tokenResult.authorizationToken;
|
|
556
379
|
}
|
|
557
380
|
// Step 1: Validate existing token
|
|
558
381
|
if (hasToken && connConfig?.authorizationToken) {
|
|
@@ -566,25 +389,44 @@ class AuthBroker {
|
|
|
566
389
|
return connConfig.authorizationToken;
|
|
567
390
|
}
|
|
568
391
|
}
|
|
569
|
-
// Step 2:
|
|
570
|
-
this.logger?.debug(`Step 2:
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
392
|
+
// Step 2: Request tokens via provider, preferring session auth config
|
|
393
|
+
this.logger?.debug(`Step 2: Requesting tokens for ${destination}`);
|
|
394
|
+
let lastError = null;
|
|
395
|
+
if (authConfig) {
|
|
396
|
+
if (!this.allowBrowserAuth && !authConfig.refreshToken) {
|
|
397
|
+
const error = new Error(`Browser authentication required for destination "${destination}" but allowBrowserAuth is disabled. Session has no refresh token.`);
|
|
398
|
+
error.code = 'BROWSER_AUTH_REQUIRED';
|
|
399
|
+
error.destination = destination;
|
|
400
|
+
this.logger?.error(`Step 2: Browser auth required but disabled for ${destination}`);
|
|
401
|
+
throw error;
|
|
402
|
+
}
|
|
575
403
|
try {
|
|
576
|
-
|
|
404
|
+
const tokenResult = await this.requestTokens(destination, 'session');
|
|
405
|
+
await this.persistTokenResult(destination, serviceUrl, connConfig, authConfig, tokenResult);
|
|
406
|
+
return tokenResult.authorizationToken;
|
|
577
407
|
}
|
|
578
408
|
catch (error) {
|
|
579
|
-
|
|
580
|
-
|
|
409
|
+
lastError = error instanceof Error ? error : new Error(String(error));
|
|
410
|
+
this.logger?.debug(`Step 2: Token request via session failed for ${destination}: ${getErrorMessage(error)}, trying service key`);
|
|
581
411
|
}
|
|
582
412
|
}
|
|
583
|
-
|
|
584
|
-
|
|
413
|
+
if (!this.allowBrowserAuth) {
|
|
414
|
+
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.`);
|
|
415
|
+
error.code = 'BROWSER_AUTH_REQUIRED';
|
|
416
|
+
error.destination = destination;
|
|
417
|
+
this.logger?.error(`Step 2: Browser auth required but disabled for ${destination}`);
|
|
418
|
+
throw error;
|
|
419
|
+
}
|
|
420
|
+
if (!this.serviceKeyStore) {
|
|
421
|
+
if (lastError) {
|
|
422
|
+
throw lastError;
|
|
423
|
+
}
|
|
424
|
+
throw new Error(`Authorization config not found for ${destination}. Session has no auth config and serviceKeyStore is not available.`);
|
|
585
425
|
}
|
|
586
|
-
|
|
587
|
-
|
|
426
|
+
const serviceKeyAuthConfig = await this.getAuthorizationConfigFromServiceKey(destination);
|
|
427
|
+
const tokenResult = await this.requestTokens(destination, 'serviceKey');
|
|
428
|
+
await this.persistTokenResult(destination, serviceUrl, connConfig, serviceKeyAuthConfig, tokenResult);
|
|
429
|
+
return tokenResult.authorizationToken;
|
|
588
430
|
}
|
|
589
431
|
/**
|
|
590
432
|
* Force refresh token for destination.
|
package/dist/index.d.ts
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
*/
|
|
5
5
|
export type { AuthType, ILogger, ITokenRefresher, } from '@mcp-abap-adt/interfaces';
|
|
6
6
|
export { AuthBroker, type AuthBrokerConfig } from './AuthBroker';
|
|
7
|
-
export type { ITokenProvider,
|
|
7
|
+
export type { ITokenProvider, ITokenResult, TokenProviderOptions, } from './providers';
|
|
8
8
|
export type { IAuthorizationConfig, IConnectionConfig, IServiceKeyStore, ISessionStore, } from './stores/interfaces';
|
|
9
9
|
export type { IConfig } from './types';
|
|
10
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;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,
|
|
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,YAAY,EACZ,oBAAoB,GACrB,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"}
|
|
@@ -1,13 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Token Provider interface
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
* Different implementations handle different authentication flows:
|
|
6
|
-
* - XSUAA: client_credentials grant type (no browser)
|
|
7
|
-
* - BTP/ABAP: browser-based OAuth2 or refresh token
|
|
4
|
+
* Stateful providers handle token lifecycle internally (refresh/relogin).
|
|
8
5
|
*/
|
|
9
|
-
import type { IAuthorizationConfig, IConnectionConfig, ITokenProvider, ITokenProviderOptions,
|
|
10
|
-
export type { ITokenProvider, IAuthorizationConfig, IConnectionConfig };
|
|
11
|
-
export type TokenProviderResult = ITokenProviderResult;
|
|
6
|
+
import type { IAuthorizationConfig, IConnectionConfig, ITokenProvider, ITokenProviderOptions, ITokenResult } from '@mcp-abap-adt/interfaces';
|
|
7
|
+
export type { ITokenProvider, IAuthorizationConfig, IConnectionConfig, ITokenResult, };
|
|
12
8
|
export type TokenProviderOptions = ITokenProviderOptions;
|
|
13
9
|
//# sourceMappingURL=ITokenProvider.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ITokenProvider.d.ts","sourceRoot":"","sources":["../../src/providers/ITokenProvider.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"ITokenProvider.d.ts","sourceRoot":"","sources":["../../src/providers/ITokenProvider.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,KAAK,EACV,oBAAoB,EACpB,iBAAiB,EACjB,cAAc,EACd,qBAAqB,EACrB,YAAY,EACb,MAAM,0BAA0B,CAAC;AAGlC,YAAY,EACV,cAAc,EACd,oBAAoB,EACpB,iBAAiB,EACjB,YAAY,GACb,CAAC;AACF,MAAM,MAAM,oBAAoB,GAAG,qBAAqB,CAAC"}
|
|
@@ -2,9 +2,6 @@
|
|
|
2
2
|
/**
|
|
3
3
|
* Token Provider interface
|
|
4
4
|
*
|
|
5
|
-
*
|
|
6
|
-
* Different implementations handle different authentication flows:
|
|
7
|
-
* - XSUAA: client_credentials grant type (no browser)
|
|
8
|
-
* - BTP/ABAP: browser-based OAuth2 or refresh token
|
|
5
|
+
* Stateful providers handle token lifecycle internally (refresh/relogin).
|
|
9
6
|
*/
|
|
10
7
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
@@ -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,
|
|
7
|
+
export type { ITokenProvider, ITokenResult, TokenProviderOptions, } 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,EACV,cAAc,EACd,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/providers/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,YAAY,EACV,cAAc,EACd,YAAY,EACZ,oBAAoB,GACrB,MAAM,kBAAkB,CAAC"}
|
package/package.json
CHANGED