@mcp-abap-adt/auth-broker 5.0.1 → 5.0.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/CHANGELOG.md +69 -0
  2. package/README.md +42 -13
  3. package/package.json +3 -3
package/CHANGELOG.md CHANGED
@@ -9,6 +9,75 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
9
9
 
10
10
  Thank you to all contributors! See [CONTRIBUTORS.md](../../CONTRIBUTORS.md) for the complete list.
11
11
 
12
+ ## [5.0.5] - 2026-10-12
13
+
14
+ The library's code and runtime dependencies are the same as 5.0.4. What changed is the
15
+ docs, the README's connection note included, and the tests.
16
+
17
+ ### Changed
18
+ - The tests and live checks run on `@mcp-abap-adt/connection` 15.0.0 (dev dependency
19
+ `^15.0.0`, on `@mcp-abap-adt/interfaces-adt-connection` 2.0.0, one copy). Their
20
+ end-to-end suite is renamed `adtConnector.test.ts`.
21
+ - The docs name `connection` 14 or 15 as the connector `getProvider`'s provider is for.
22
+ The README says why a consumer that also uses `adt-clients` should take 15.
23
+
24
+ ## [5.0.4] - 2026-10-12
25
+
26
+ The first published release after 5.0.1. The code is the same as 5.0.2 and 5.0.3, which were
27
+ tagged but not published. It is released together with auth-broker-cli 3.1.1, so that one
28
+ publish from the main checkout carries both. 5.0.2 (built and tested on auth-stores 5) and
29
+ 5.0.3 (tests on connection 14.1.0, the README's connection note) arrive with 5.0.4.
30
+
31
+ ## [5.0.3] - 2026-10-12
32
+
33
+ Development only; the published library is unchanged.
34
+
35
+ ### Changed
36
+ - The tests run on `@mcp-abap-adt/connection` 14.1.0 (a dev dependency, `^14.1.0`):
37
+ its `disconnect()` sends the session's logoff, so a connection the broker's
38
+ tests and live checks close no longer leaves its SAP session open until the
39
+ server's timeout. The connection is the consumer's; the broker does not
40
+ depend on it.
41
+ - README: a consumer should use `@mcp-abap-adt/connection` 14.1.0 or later. From
42
+ 14.1.0, `disconnect()` ends the SAP session.
43
+
44
+ ## [5.0.2] - 2026-10-11
45
+
46
+ Built and tested on `@mcp-abap-adt/auth-stores` 5.0.0; the code is the same as
47
+ 5.0.1. auth-stores is not a dependency of the library: the consumer composes
48
+ the stores, and 5.0.2 works with auth-stores 4 or 5 alike.
49
+
50
+ ### Migration (for a consumer moving to auth-stores 5)
51
+
52
+ - **A session file with no binding keys beside its credential** — written by
53
+ auth-stores 2.x/3.0.0, auth-broker 3.x, or by hand — is no longer composed a
54
+ binding by the store and read as unbound (one login). auth-stores 5 refuses
55
+ the record whole with a `StorageError` (`code: 'STORAGE_ERROR'`,
56
+ `reason: 'record-format'`, fixed words, no value of the record), and the
57
+ broker passes it unchanged to the caller of `getProvider` and the token API
58
+ (every row that reads the session; the broker's own `client_credentials`
59
+ reads none, and its new credential replaces the record). This is 5.0.0's
60
+ rule that a store's read failure other than `FILE_NOT_FOUND` reaches the
61
+ caller, not a change of the broker.
62
+ - **What to do:** regenerate the session with
63
+ `mcp-auth --service-key <key.json> --output <file> --type abap|xsuaa`, or
64
+ remove its session lines; a file holding only the means is no session.
65
+ `@mcp-abap-adt/auth-broker-cli` 3.1.0 (released together) does it for you:
66
+ `mcp-auth --env <file>` or `--destination <name>` over such a file discards
67
+ its session and logs in anew, the means kept byte for byte.
68
+
69
+ ### Changed
70
+ - Dev dependency `@mcp-abap-adt/auth-stores` ^5.0.0.
71
+ - Tests: a pre-3.1.0 session file, and a 4.x token beside `issuedFor` alone,
72
+ now assert the store's `record-format` error reaching the caller — no
73
+ request, no login, no write, the file byte for byte, no record value in the
74
+ error or the log — where they asserted a login over a composed binding.
75
+
76
+ ### Documentation
77
+ - README (*Errors*, *A Credential Stays Bound to Its Identity*, the upgrade
78
+ note), `docs/` and `CLAUDE.md` describe the record-format refusal and name
79
+ auth-stores 5.
80
+
12
81
  ## [5.0.1] - 2026-10-09
13
82
 
14
83
  Development only; the code is the same as 5.0.0.
package/README.md CHANGED
@@ -4,7 +4,7 @@
4
4
  A per-destination credential broker for SAP BTP and ABAP systems. For a destination — a name,
5
5
  such as `TRIAL` — `getProvider` builds the `IAuthProvider` the destination states (basic, SNC, a
6
6
  UAA, OIDC or SAML grant, or a credential handed over) from the *means* in the service key store
7
- and the *secret* in the session store, ready for a `@mcp-abap-adt/connection` 14 connector, and
7
+ and the *secret* in the session store, ready for a `@mcp-abap-adt/connection` 14 or 15 connector, and
8
8
  stores back every token or set of SAML session cookies that provider obtains or renews. The
9
9
  token API (`getToken`, `refreshToken`, `createTokenRefresher`) serves whoever wants a token and
10
10
  nothing else. It decides nothing about tokens itself: whether the cached token is still good,
@@ -16,10 +16,14 @@ the renewal strategy's you give it; where means and secrets live is the stores'
16
16
  short — a token destination needs two options the broker has no default for (`renewal`,
17
17
  `onWriteFailure`); every failure is an `AuthProviderFailure` read through
18
18
  `@mcp-abap-adt/auth-errors`; every session written before 5.0.0 reads as unbound once, so each
19
- token destination logs in once after the upgrade.
19
+ token destination logs in once after the upgrade. A session file with no binding keys at all
20
+ (written before auth-stores 3.1.0, or by hand) is refused by auth-stores 5 as a whole, and that
21
+ error reaches you: regenerate it with `mcp-auth` (see [*Errors*](#errors)) — from
22
+ auth-broker-cli 3.1.1, `mcp-auth --env <file>` (or `--destination <name>`) over such a file
23
+ discards its session and logs in anew.
20
24
 
21
25
  The `mcp-auth` command that writes destination files is
22
- [`@mcp-abap-adt/auth-broker-cli`](../auth-broker-cli/README.md) (3.0.0, on this version), in the
26
+ [`@mcp-abap-adt/auth-broker-cli`](../auth-broker-cli/README.md) (3.1.1, on this version), in the
23
27
  same repository. This package has no `bin`.
24
28
 
25
29
  ## Features
@@ -39,8 +43,8 @@ same repository. This package has no `bin`.
39
43
  npm install @mcp-abap-adt/auth-broker @mcp-abap-adt/auth-providers @mcp-abap-adt/auth-errors @mcp-abap-adt/auth-stores
40
44
  ```
41
45
 
42
- 5.0.0 depends on `@mcp-abap-adt/auth-providers` `^6.0.0`, `@mcp-abap-adt/auth-errors`
43
- `^2.1.1`, `@mcp-abap-adt/interfaces-auth` `^7.5.0`, `@mcp-abap-adt/interfaces-auth-sap`
46
+ 5.0.5 depends on `@mcp-abap-adt/auth-providers` `^6.0.0`, `@mcp-abap-adt/auth-errors`
47
+ `^2.2.0`, `@mcp-abap-adt/interfaces-auth` `^7.5.0`, `@mcp-abap-adt/interfaces-auth-sap`
44
48
  `^3.3.0`, `@mcp-abap-adt/interfaces-auth-broker` `^1.3.0` and
45
49
  `@mcp-abap-adt/interfaces-utils` `^1.1.0`. Declare `auth-providers` yourself — the renewal
46
50
  strategies (`refreshThenLogin`, `refreshOnly`) and the interactive strategies come from it —
@@ -96,7 +100,7 @@ const provider = await broker.getProvider('TRIAL', { signal: session.signal });
96
100
  ```
97
101
 
98
102
  `getProvider(destination)` returns the `IAuthProvider` (from `@mcp-abap-adt/interfaces-auth`
99
- 7) that a `@mcp-abap-adt/connection` 14 connector takes as it is. The broker reads two stores,
103
+ 7) that a `@mcp-abap-adt/connection` 14 or 15 connector takes as it is. The broker reads two stores,
100
104
  each for one role:
101
105
 
102
106
  - **the means** — `authType`, `grantType`, basic's user and password, the SNC, OIDC and SAML
@@ -312,7 +316,7 @@ success — and the write runs on, landing or failing on its own.
312
316
 
313
317
  **The store's contract.** `saveSession` settles: it resolves or rejects. A store whose
314
318
  `saveSession` never settles holds its destination's queue; avoiding that is yours (each waiting
315
- caller is still released by its own signal). auth-stores 4's `saveSession` **merges** — a field
319
+ caller is still released by its own signal). auth-stores 5's `saveSession` **merges** — a field
316
320
  left out keeps what is stored — so the broker states every field that must not survive:
317
321
 
318
322
  | What the provider reported | What one `saveSession` writes |
@@ -439,6 +443,18 @@ means lacking what the record needs, or no `serviceUrl`) gets a `debug` line ins
439
443
  start. An OIDC destination with explicit endpoints and a client but no issuer is fully stated,
440
444
  and is reused after a restart when its means are unchanged.
441
445
 
446
+ **A record the store refuses is not "no session".** auth-stores 5 reads a session only in its
447
+ own format — beside a token or cookies, both binding keys (`SAP_ISSUED_FOR` / `SAP_ISSUED_BY`,
448
+ or the `XSUAA_*` pair), present even when empty — and refuses any other record as a whole with
449
+ a `StorageError` (`reason: 'record-format'`): a file written by auth-stores 2.x/3.0.0 or
450
+ auth-broker 3.x, or by hand. The broker does not read that as an absent session and log in over
451
+ it; `getProvider` and the token API reject with the store's error, unchanged, before any
452
+ request (every row that reads the session; the broker's own `client_credentials` reads none,
453
+ and its new credential replaces the record). Regenerate the session with `mcp-auth`: from
454
+ auth-broker-cli 3.1.1, a run over the file (`--env`, `--destination`) discards its session — the
455
+ session keys alone, in a private copy, the original written only after the new login is stored —
456
+ and logs in anew.
457
+
442
458
  **The `none` rows** present a credential the broker cannot obtain again, so a mismatch is
443
459
  refused, not discarded: a `DestinationConfigError` naming `issuedFor` when the stored resource
444
460
  differs or is absent (or the means state no `serviceUrl`), and `issuedBy` when the stored record
@@ -468,7 +484,7 @@ import { bindingOf } from '@mcp-abap-adt/auth-broker';
468
484
  const means = await keyStore.getConnectionConfig('DEV'); // saml / none
469
485
  await sessionStore.saveSession('DEV', {
470
486
  sessionCookies: cookies,
471
- refreshToken: '', // auth-stores 4 merges: clear what an earlier session left
487
+ refreshToken: '', // auth-stores 5 merges: clear what an earlier session left
472
488
  ...bindingOf(means ?? {}),
473
489
  // { issuedFor: 'https://dev.example.com:443?sap-client=100',
474
490
  // issuedBy: 'mcp-abap-adt-binding/2;saml/none;;;;;;;;;;;;' }
@@ -826,9 +842,16 @@ const current = await tokenRefresher.getToken();
826
842
  const renewed = await tokenRefresher.refreshToken();
827
843
  ```
828
844
 
829
- A `@mcp-abap-adt/connection` 14 connector takes an `IAuthProvider` instead: give it `await
845
+ A `@mcp-abap-adt/connection` 14 or 15 connector takes an `IAuthProvider` instead: give it `await
830
846
  broker.getProvider('TRIAL', { signal })`.
831
847
 
848
+ Use `@mcp-abap-adt/connection` 14.1.0 or later. From 14.1.0 its `disconnect()` sends the
849
+ session's logoff. An earlier 14.x left each closed connection's SAP session open until the
850
+ server's own timeout, so a process that connects again and again collects sessions.
851
+ Connection 15 is built on `@mcp-abap-adt/interfaces-adt-connection` 2, as `adt-clients` is.
852
+ If your consumer uses both, choose 15: with 14 it installs two copies of that contract.
853
+ The broker hands either one the same `IAuthProvider`.
854
+
832
855
  ## Errors
833
856
 
834
857
  **A provider's failure passes as the same object.** Whatever a provider throws from
@@ -930,7 +953,13 @@ needs a clientAuthentication strategy`.
930
953
 
931
954
  - **A store's read failure** (anything but `FILE_NOT_FOUND`, which is absence) reaches the
932
955
  caller as the store raised it — your collaborator's error, returned to you, also through the
933
- shared resolution. A store that answers `null`, or fails with `FILE_NOT_FOUND` (logged at
956
+ shared resolution. With auth-stores 5 that includes a session record not of the store's
957
+ format: a `StorageError` with `code: 'STORAGE_ERROR'` and `reason: 'record-format'`, in the
958
+ store's fixed words (`AbapSessionStore: the stored session for "<destination>" is not in this
959
+ store's format; regenerate it with mcp-auth`) — no value of the record. Regenerate the session
960
+ (`mcp-auth --service-key <key.json> --output <file>`, or from auth-broker-cli 3.1.1
961
+ `mcp-auth --env <file>`, which discards the refused session and logs in anew), or remove its
962
+ session lines. A store that answers `null`, or fails with `FILE_NOT_FOUND` (logged at
934
963
  debug), means "nothing here".
935
964
  - **The constructor's argument checks** (`AuthBroker: sessionStore is required`, …) are plain
936
965
  `Error`s naming option names: a programming error.
@@ -983,7 +1012,7 @@ its level from `AUTH_LOG_LEVEL`.)
983
1012
 
984
1013
  ### File Structure
985
1014
 
986
- With `@mcp-abap-adt/auth-stores` 4 one `<destination>.env` file can hold a destination whole,
1015
+ With `@mcp-abap-adt/auth-stores` 5 one `<destination>.env` file can hold a destination whole,
987
1016
  each store reading and writing only its own keys — the means through `EnvDestinationStore`, the
988
1017
  secret through `AbapSessionStore` (or both in separate directories, as you compose them):
989
1018
 
@@ -1171,7 +1200,7 @@ What a 4.x consumer must now do, row by row. The full list of changes is the
1171
1200
 
1172
1201
  | 4.x | 5.0.0 — what to do |
1173
1202
  |---|---|
1174
- | `@mcp-abap-adt/auth-providers` 5, `interfaces-auth` 3, `auth-stores` 3 | auth-providers `^6.0.0`, interfaces-auth `^7.5.0`, auth-errors `^2.1.1`, auth-stores `^4.0.0`; one installed copy of each contract (`npm ls`) |
1203
+ | `@mcp-abap-adt/auth-providers` 5, `interfaces-auth` 3, `auth-stores` 3 | auth-providers `^6.0.0`, interfaces-auth `^7.5.0`, auth-errors `^2.1.1`, auth-stores `^4.0.0` (`^5.0.0` from 5.0.4, the first published since 5.0.1: a session record without binding keys is refused, see *Errors*); one installed copy of each contract (`npm ls`) |
1175
1204
  | token rows renewed by the provider's built-in rule | pass `renewal: () => refreshThenLogin()` — 4.x's steps; without `renewal` a token row is refused (`missingFields: ['renewal']`) |
1176
1205
  | a `getProvider` provider's failed write never failed the authentication; the token API threw the store's error | pass `onWriteFailure`: `'continue'` keeps 4.x's connector behaviour (best effort); `'fail'` keeps 4.x's token-API behaviour and extends it to the connector and to every later call of the destination while the write is pending. Without it a destination that writes a secret is refused |
1177
1206
  | errors of the token API: auth-providers 5.x classes (`ValidationError`, `BrowserAuthError`, `RefreshError`, …) | `AuthProviderFailure`: read it with `readFailure(error, operation)` and `matchKind` (auth-errors); auth-providers' *Migrating to 6.0.0* maps each class to its kind |
@@ -1215,7 +1244,7 @@ npm test -w @mcp-abap-adt/auth-broker -- AuthBroker.test.ts -t "name of the case
1215
1244
  ```
1216
1245
 
1217
1246
  Tests run sequentially (`maxWorkers: 1`, `maxConcurrency: 1`). The broker suites need nothing:
1218
- fake stores of the contract or auth-stores 4 in temporary directories, real providers, a token
1247
+ fake stores of the contract or auth-stores 5 in temporary directories, real providers, a token
1219
1248
  endpoint the test starts on `127.0.0.1`. `AuthBroker.integration.test.ts` reads real service
1220
1249
  keys and sessions only when `packages/auth-broker/tests/test-config.yaml` exists (from the
1221
1250
  template beside it); without it every case returns at once. The stand (`npm run test:stand`,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mcp-abap-adt/auth-broker",
3
- "version": "5.0.1",
3
+ "version": "5.0.5",
4
4
  "description": "Per-destination credential broker for SAP BTP and ABAP: the IAuthProvider a destination states, built from its key store and session store, with every secret it obtains stored back; and a token API",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -65,8 +65,8 @@
65
65
  },
66
66
  "devDependencies": {
67
67
  "@mcp-abap-adt/auth-mocks": "^0.4.0",
68
- "@mcp-abap-adt/auth-stores": "^4.0.0",
69
- "@mcp-abap-adt/connection": "^14.0.0",
68
+ "@mcp-abap-adt/auth-stores": "^5.0.0",
69
+ "@mcp-abap-adt/connection": "^15.0.0",
70
70
  "@mcp-abap-adt/logger": "^0.4.0",
71
71
  "@types/js-yaml": "^4.0.9",
72
72
  "js-yaml": "^4.1.1",