@nevermined-io/payments 1.13.0 → 1.14.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/dist/a2a/paymentsRequestHandler.d.ts +5 -1
- package/dist/a2a/paymentsRequestHandler.d.ts.map +1 -1
- package/dist/a2a/paymentsRequestHandler.js +156 -13
- package/dist/a2a/paymentsRequestHandler.js.map +1 -1
- package/dist/a2a/types.d.ts +25 -0
- package/dist/a2a/types.d.ts.map +1 -1
- package/dist/a2a/types.js.map +1 -1
- package/dist/api/agents-api.d.ts +4 -3
- package/dist/api/agents-api.d.ts.map +1 -1
- package/dist/api/agents-api.js +7 -4
- package/dist/api/agents-api.js.map +1 -1
- package/dist/api/base-payments.d.ts +7 -2
- package/dist/api/base-payments.d.ts.map +1 -1
- package/dist/api/base-payments.js +15 -8
- package/dist/api/base-payments.js.map +1 -1
- package/dist/api/nvm-api.d.ts +5 -5
- package/dist/api/observability-api/types.d.ts +34 -6
- package/dist/api/observability-api/types.d.ts.map +1 -1
- package/dist/api/observability-api/types.js.map +1 -1
- package/dist/api/plans-api.d.ts +15 -12
- package/dist/api/plans-api.d.ts.map +1 -1
- package/dist/api/plans-api.js +17 -14
- package/dist/api/plans-api.js.map +1 -1
- package/dist/api/query-api.d.ts +1 -1
- package/dist/common/types.d.ts +88 -18
- package/dist/common/types.d.ts.map +1 -1
- package/dist/common/types.js.map +1 -1
- package/dist/mcp/core/paywall.d.ts.map +1 -1
- package/dist/mcp/core/paywall.js +59 -8
- package/dist/mcp/core/paywall.js.map +1 -1
- package/dist/mcp/http/index.d.ts +1 -1
- package/dist/mcp/http/index.d.ts.map +1 -1
- package/dist/mcp/http/index.js +1 -1
- package/dist/mcp/http/index.js.map +1 -1
- package/dist/mcp/http/oauth-metadata.d.ts +32 -0
- package/dist/mcp/http/oauth-metadata.d.ts.map +1 -1
- package/dist/mcp/http/oauth-metadata.js +329 -34
- package/dist/mcp/http/oauth-metadata.js.map +1 -1
- package/dist/mcp/index.d.ts +4 -4
- package/dist/mcp/index.d.ts.map +1 -1
- package/dist/mcp/index.js +5 -5
- package/dist/mcp/index.js.map +1 -1
- package/dist/mcp/types/http.types.d.ts +38 -3
- package/dist/mcp/types/http.types.d.ts.map +1 -1
- package/dist/mcp/types/http.types.js.map +1 -1
- package/dist/mcp/types/paywall.types.d.ts +19 -3
- package/dist/mcp/types/paywall.types.d.ts.map +1 -1
- package/dist/mcp/types/paywall.types.js.map +1 -1
- package/dist/payments.d.ts.map +1 -1
- package/dist/x402/delegation-api.d.ts +5 -17
- package/dist/x402/delegation-api.d.ts.map +1 -1
- package/dist/x402/delegation-api.js +2 -2
- package/dist/x402/delegation-api.js.map +1 -1
- package/package.json +22 -13
|
@@ -4,22 +4,236 @@
|
|
|
4
4
|
* without any framework dependencies, making them reusable across different HTTP servers.
|
|
5
5
|
*/
|
|
6
6
|
import { Environments } from '../../environments.js';
|
|
7
|
+
/**
|
|
8
|
+
* The query parameter that tells the Nevermined web app WHICH API tier an OAuth ceremony belongs
|
|
9
|
+
* to, and its two values. Each tier (sandbox / live) is its own authorization server, but ONE web
|
|
10
|
+
* app serves the consent screens for both and boots on whatever tier the user's browser last chose
|
|
11
|
+
* — Live by default. A bare `https://nevermined.app/oauth/authorize` therefore sends a sandbox MCP
|
|
12
|
+
* server's users to the LIVE consent screen, where the connector is not registered ("Connector not
|
|
13
|
+
* authorized"). The tier is stated on the URL instead; RFC 6749 §3.1 obliges clients to retain the
|
|
14
|
+
* query component when they add their own parameters. Same name and values as the Nevermined API's
|
|
15
|
+
* own RFC 8414 document and the embed widget (nvm-monorepo#3430 / #1787).
|
|
16
|
+
*/
|
|
17
|
+
export const OAUTH_TIER_PARAM = 'network';
|
|
18
|
+
export const OAUTH_TIERS = ['sandbox', 'live'];
|
|
19
|
+
/**
|
|
20
|
+
* The API tier an environment belongs to. The four named environments map directly. `custom` is
|
|
21
|
+
* derived from the host of the backend it will publish as `token_endpoint`: a Nevermined API host has
|
|
22
|
+
* an `api` label immediately followed by the tier label — `api.sandbox.nevermined.app`,
|
|
23
|
+
* `<slug>.api.live.nevermined.app` (branded per-org subdomains), `mcp.api.sandbox.nevermined.dev` —
|
|
24
|
+
* so that label pair is what is matched, never a bare `sandbox` anywhere in the host. When the host
|
|
25
|
+
* cannot be classified (a `localhost` stack, a proxy/CNAME in front of the API) the tier is
|
|
26
|
+
* **omitted**, not guessed: the URL stays the pre-#3430 bare one, and the operator sets
|
|
27
|
+
* `oauthUrls.authorizationUri` (with `?network=` on it) to say which tier that deployment is —
|
|
28
|
+
* `getOAuthUrlsForEnvironment` warns once when that happens, so the degradation is never silent.
|
|
29
|
+
*
|
|
30
|
+
* ⚠️ This is not the only classifier of a `custom` backend for the `network` value — the CLI's
|
|
31
|
+
* `resolveEmbedNetwork` (`cli/src/utils/widget-redirect-flow.ts`) and nvm-monorepo's
|
|
32
|
+
* `deriveEmbedNetwork` (`apps/mcp/src/config.ts`) classify the same input. All three now apply THIS
|
|
33
|
+
* rule — the `api.<tier>` label pair, never guessing (the CLI ports it verbatim, payments#456; the
|
|
34
|
+
* monorepo via the shared `oauthTierFromHostname`, nvm-monorepo#3638). Keep them in sync; do not
|
|
35
|
+
* derive a fourth rule here.
|
|
36
|
+
*/
|
|
37
|
+
export function resolveOAuthTier(environment, backendUrl) {
|
|
38
|
+
switch (environment) {
|
|
39
|
+
case 'sandbox':
|
|
40
|
+
case 'staging_sandbox':
|
|
41
|
+
return 'sandbox';
|
|
42
|
+
case 'live':
|
|
43
|
+
case 'staging_live':
|
|
44
|
+
return 'live';
|
|
45
|
+
default:
|
|
46
|
+
return tierFromHost(backendUrl);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* The `api.<tier>` label-pair match behind {@link resolveOAuthTier}'s `custom` branch: the FIRST
|
|
51
|
+
* `api` label that a tier label FOLLOWS — not the first `api` label, full stop. The two differ on
|
|
52
|
+
* one served shape: an org slugged `api` (legal today) gets the branded host
|
|
53
|
+
* `api.api.live.nevermined.app`, which `labels[indexOf('api') + 1]` read as `api` and refused.
|
|
54
|
+
* Same rule as nvm-monorepo's shared `oauthTierFromHostname` (`@nevermined-io/commons`), so the
|
|
55
|
+
* SDK, the Commerce MCP and the API classify a host identically (payments#468).
|
|
56
|
+
*/
|
|
57
|
+
function tierFromHost(url) {
|
|
58
|
+
let labels;
|
|
59
|
+
try {
|
|
60
|
+
// WHATWG `hostname` is lowercased and carries no port/credentials/path.
|
|
61
|
+
labels = new URL(url).hostname.split('.');
|
|
62
|
+
}
|
|
63
|
+
catch {
|
|
64
|
+
return undefined;
|
|
65
|
+
}
|
|
66
|
+
for (let i = 0; i + 1 < labels.length; i++) {
|
|
67
|
+
if (labels[i] === 'api' && OAUTH_TIERS.includes(labels[i + 1])) {
|
|
68
|
+
return labels[i + 1];
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
return undefined;
|
|
72
|
+
}
|
|
73
|
+
/** Best-effort host for a warning line; never throws on a malformed URL. */
|
|
74
|
+
function hostOf(url) {
|
|
75
|
+
try {
|
|
76
|
+
return new URL(url).host;
|
|
77
|
+
}
|
|
78
|
+
catch {
|
|
79
|
+
return url;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
// Warn-once flags, module-level like `environmentOptionDeprecationWarned` in `base-payments.ts`:
|
|
83
|
+
// discovery documents are rebuilt per request, and a warning per request is noise nobody reads.
|
|
84
|
+
let tierlessWarned = false;
|
|
85
|
+
let crossTierWarned = false;
|
|
86
|
+
/**
|
|
87
|
+
* Append `?network=<tier>` to the authorize URL. Goes through the URL API so the result is a
|
|
88
|
+
* canonical absolute URL with one query string; a frontend that is not an absolute URL (a relative
|
|
89
|
+
* `NVM_FRONTEND_URL` such as `/webapp`) cannot be parsed, and falls back to plain concatenation —
|
|
90
|
+
* the same shape the tier-less URL always had for that misconfiguration.
|
|
91
|
+
*/
|
|
92
|
+
function withTierParam(authorizeUrl, tier) {
|
|
93
|
+
if (!tier)
|
|
94
|
+
return authorizeUrl;
|
|
95
|
+
try {
|
|
96
|
+
const url = new URL(authorizeUrl);
|
|
97
|
+
url.searchParams.set(OAUTH_TIER_PARAM, tier);
|
|
98
|
+
return url.toString();
|
|
99
|
+
}
|
|
100
|
+
catch {
|
|
101
|
+
return `${authorizeUrl}${authorizeUrl.includes('?') ? '&' : '?'}${OAUTH_TIER_PARAM}=${tier}`;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* The ORIGIN of a URL — `new URL(u).origin` — or `undefined` when the string does not parse or
|
|
106
|
+
* parses to an opaque origin: `new URL('localhost:3001')` succeeds (scheme `localhost:`) with
|
|
107
|
+
* `.origin === 'null'`, which can never be an RFC 8414 issuer.
|
|
108
|
+
*/
|
|
109
|
+
function originOf(url) {
|
|
110
|
+
try {
|
|
111
|
+
const origin = new URL(url).origin;
|
|
112
|
+
return origin === 'null' ? undefined : origin;
|
|
113
|
+
}
|
|
114
|
+
catch {
|
|
115
|
+
return undefined;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* The canonical Nevermined API origin a backend host stands for, or `undefined` for a host that
|
|
120
|
+
* is not a Nevermined API. `<slug>.api.live.nevermined.app` (a branded per-org subdomain) and
|
|
121
|
+
* `mcp.api.sandbox.nevermined.dev` both serve the same API as `api.<tier>.nevermined.<tld>` — and
|
|
122
|
+
* that canonical origin is what the two parties an issuer must agree with actually use: the API's
|
|
123
|
+
* own RFC 8414 document anchors `issuer` on `API_HOST`, never the request host, and the web app
|
|
124
|
+
* returns RFC 9207 `iss` from its fixed per-tier config. Publishing the branded origin as `issuer`
|
|
125
|
+
* would fail every RFC 9207 client's simple-string compare (payments#464 review). The suffix
|
|
126
|
+
* requirement is deliberate: it derives a HOST, and only a Nevermined host has a canonical form.
|
|
127
|
+
*/
|
|
128
|
+
function canonicalNeverminedOrigin(backendUrl) {
|
|
129
|
+
const tier = tierFromHost(backendUrl);
|
|
130
|
+
if (!tier)
|
|
131
|
+
return undefined;
|
|
132
|
+
let hostname;
|
|
133
|
+
try {
|
|
134
|
+
// A trailing-dot FQDN (`api.sandbox.nevermined.app.`) is the same host to DNS; keep the suffix
|
|
135
|
+
// checks from missing it and republishing a one-byte-off issuer.
|
|
136
|
+
hostname = new URL(backendUrl).hostname.replace(/\.$/, '');
|
|
137
|
+
}
|
|
138
|
+
catch {
|
|
139
|
+
return undefined;
|
|
140
|
+
}
|
|
141
|
+
let environment;
|
|
142
|
+
if (hostname.endsWith('.nevermined.app'))
|
|
143
|
+
environment = tier;
|
|
144
|
+
else if (hostname.endsWith('.nevermined.dev'))
|
|
145
|
+
environment = tier === 'live' ? 'staging_live' : 'staging_sandbox';
|
|
146
|
+
return environment ? originOf(Environments[environment].backend) : undefined;
|
|
147
|
+
}
|
|
148
|
+
// Warned once per DISTINCT value (a changed typo re-alerts), and never when the operator has
|
|
149
|
+
// already set `oauthUrls.issuer` — the remedy the warning names.
|
|
150
|
+
const issuerWarned = new Set();
|
|
151
|
+
function isLoopback(origin) {
|
|
152
|
+
try {
|
|
153
|
+
const host = new URL(origin).hostname;
|
|
154
|
+
return host === 'localhost' || host === '127.0.0.1' || host === '[::1]';
|
|
155
|
+
}
|
|
156
|
+
catch {
|
|
157
|
+
return false;
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
function warnIssuerOnce(key, message) {
|
|
161
|
+
if (issuerWarned.has(key))
|
|
162
|
+
return;
|
|
163
|
+
issuerWarned.add(key);
|
|
164
|
+
console.warn(message);
|
|
165
|
+
}
|
|
166
|
+
/**
|
|
167
|
+
* The RFC 8414 issuer identifier of the authorization server a document describes.
|
|
168
|
+
*
|
|
169
|
+
* It is the ORIGIN of the Nevermined API the document points at — the value the API's own
|
|
170
|
+
* document publishes and the web app returns as RFC 9207 `iss` on every authorization response,
|
|
171
|
+
* which an RFC 9207 client compares with the discovered `issuer` by SIMPLE STRING comparison and
|
|
172
|
+
* rejects on any difference. So it has to be the canonical origin, byte for byte:
|
|
173
|
+
* - a NAMED environment is that identity — its canonical backend origin, whatever `tokenUri`
|
|
174
|
+
* override sits in front of it (a same-tier proxy is still the same authorization server; a
|
|
175
|
+
* cross-tier override is a misconfiguration `getOAuthUrlsForEnvironment` already warns about);
|
|
176
|
+
* - `custom` follows the backend the document PUBLISHES (a `tokenUri` override, else its own):
|
|
177
|
+
* the canonical Nevermined origin when that host classifies, else the host's own origin, else —
|
|
178
|
+
* unparsable or opaque — the environment backend's origin, else the raw string minus its
|
|
179
|
+
* trailing slash, warned once. A metadata endpoint never throws.
|
|
180
|
+
*/
|
|
181
|
+
function issuerFor(effective, publishedBackend, envBackend, issuerOverridden) {
|
|
182
|
+
if (effective !== 'custom') {
|
|
183
|
+
// Every named environment's backend is a canonical absolute URL (`src/environments.ts`).
|
|
184
|
+
return originOf(envBackend) ?? envBackend.replace(/\/$/, '');
|
|
185
|
+
}
|
|
186
|
+
const canonical = canonicalNeverminedOrigin(publishedBackend);
|
|
187
|
+
if (canonical)
|
|
188
|
+
return canonical;
|
|
189
|
+
const own = originOf(publishedBackend) ?? originOf(envBackend);
|
|
190
|
+
if (own) {
|
|
191
|
+
// The right value for a genuinely foreign API — and the WRONG one for a proxy/CNAME in front
|
|
192
|
+
// of the real Nevermined API (`https://api.live.example.com` → the web app still returns
|
|
193
|
+
// `iss = https://api.live.nevermined.app`, so every RFC 9207 client rejects the code). The SDK
|
|
194
|
+
// cannot tell the two apart, so it says what it derived and names the remedy (#464 review).
|
|
195
|
+
// A loopback host is a local stack, not a proxy for the real API, and already gets the tier
|
|
196
|
+
// warning — no second line there.
|
|
197
|
+
if (!issuerOverridden && !isLoopback(own)) {
|
|
198
|
+
warnIssuerOnce(own, `[Nevermined] OAuth issuer derived from backend host '${hostOf(publishedBackend)}' as ` +
|
|
199
|
+
`'${own}'. If that host is a proxy or gateway in front of a Nevermined API rather than ` +
|
|
200
|
+
`the API itself, set oauthUrls.issuer (and oauthUrls.tokenUri) to that API's real origin — ` +
|
|
201
|
+
`otherwise the issuer will not match the iss the authorization server returns.`);
|
|
202
|
+
}
|
|
203
|
+
return own;
|
|
204
|
+
}
|
|
205
|
+
const raw = publishedBackend.replace(/\/$/, '');
|
|
206
|
+
if (!issuerOverridden) {
|
|
207
|
+
warnIssuerOnce(raw, `[Nevermined] Could not derive an OAuth issuer from backend '${publishedBackend}' — ` +
|
|
208
|
+
`publishing '${raw}'. Set oauthUrls.issuer (and oauthUrls.tokenUri) to the API origin ` +
|
|
209
|
+
`of this deployment's tier.`);
|
|
210
|
+
}
|
|
211
|
+
return raw;
|
|
212
|
+
}
|
|
7
213
|
/**
|
|
8
214
|
* Build OAuth URLs from frontend and backend URLs.
|
|
9
|
-
* -
|
|
10
|
-
* - tokenUri, jwksUri, userinfoUri use the backend (API)
|
|
215
|
+
* - authorizationUri uses the frontend (user-facing consent page) and carries the tier
|
|
216
|
+
* - issuer, tokenUri, jwksUri, userinfoUri use the backend (the API is the authorization server)
|
|
217
|
+
*
|
|
218
|
+
* `issuer` used to be the FRONTEND origin — identical for both tiers, since one web app serves both
|
|
219
|
+
* consent screens — while `authorization_servers` (RFC 9728), `token_endpoint` and the API's own
|
|
220
|
+
* RFC 8414 document all named the backend. That was a tier-blind identifier, and once the web app
|
|
221
|
+
* started returning RFC 9207 `iss` = the API origin (nvm-monorepo#3532) it made every RFC 9207
|
|
222
|
+
* client that discovers via THIS server's well-known reject its authorization responses. payments#464.
|
|
11
223
|
*
|
|
12
224
|
* @param frontendUrl - The frontend URL (e.g., https://nevermined.app)
|
|
13
225
|
* @param backendUrl - The backend URL (e.g., https://api.sandbox.nevermined.app)
|
|
226
|
+
* @param tier - The API tier to stamp on the authorize URL (see {@link resolveOAuthTier})
|
|
227
|
+
* @param issuer - The issuer identifier (see {@link issuerFor})
|
|
14
228
|
* @returns OAuth URLs configuration
|
|
15
229
|
*/
|
|
16
|
-
function buildOAuthUrls(frontendUrl, backendUrl) {
|
|
230
|
+
function buildOAuthUrls(frontendUrl, backendUrl, tier, issuer) {
|
|
17
231
|
// Remove trailing slashes
|
|
18
232
|
const frontend = frontendUrl.replace(/\/$/, '');
|
|
19
233
|
const backend = backendUrl.replace(/\/$/, '');
|
|
20
234
|
return {
|
|
21
|
-
issuer
|
|
22
|
-
authorizationUri: `${frontend}/oauth/authorize`,
|
|
235
|
+
issuer,
|
|
236
|
+
authorizationUri: withTierParam(`${frontend}/oauth/authorize`, tier),
|
|
23
237
|
tokenUri: `${backend}/oauth/token`,
|
|
24
238
|
jwksUri: `${backend}/.well-known/jwks.json`,
|
|
25
239
|
userinfoUri: `${backend}/oauth/userinfo`,
|
|
@@ -27,14 +241,51 @@ function buildOAuthUrls(frontendUrl, backendUrl) {
|
|
|
27
241
|
}
|
|
28
242
|
/**
|
|
29
243
|
* Get OAuth URLs for an environment.
|
|
30
|
-
* Uses frontend and backend URLs from Environments configuration.
|
|
244
|
+
* Uses frontend and backend URLs from Environments configuration. An unknown environment name (a
|
|
245
|
+
* JS caller / cast — `EnvironmentName` is closed) falls back to `sandbox`, as it always did; the
|
|
246
|
+
* fallback is now internally consistent (a sandbox `token_endpoint` AND a sandbox-tagged authorize).
|
|
31
247
|
*
|
|
32
248
|
* @param environment - The Nevermined environment name
|
|
249
|
+
* @param backendForTier - The backend the document will actually publish as `token_endpoint` —
|
|
250
|
+
* the environment's, or an `oauthUrls.tokenUri` override. The tier follows THAT under `custom`,
|
|
251
|
+
* exactly as `resolveAuthorizationServer` derives the AS origin from it: a `custom` server whose
|
|
252
|
+
* `tokenUri` is overridden to `api.sandbox.…` must not publish a sandbox token endpoint next to a
|
|
253
|
+
* tier-blind authorize URL (payments#455 review). Under a NAMED environment the environment's tier
|
|
254
|
+
* takes precedence over the override — deliberately: a same-tier proxy (`sandbox` +
|
|
255
|
+
* `tokenUri: https://gw.corp.com/…`) classifies to nothing and must keep the tier it has. When the
|
|
256
|
+
* override's host classifies to the OTHER tier the combination is always a misconfiguration (the
|
|
257
|
+
* consent screen on one tier, the token endpoint on the other, and the code exchange failing as a
|
|
258
|
+
* "bad or expired code"), so it is warned once rather than silently honoured. The ISSUER of a
|
|
259
|
+
* named environment never follows the override at all — see {@link issuerFor}.
|
|
33
260
|
* @returns OAuth URLs configuration
|
|
34
261
|
*/
|
|
35
|
-
function getOAuthUrlsForEnvironment(environment) {
|
|
36
|
-
const
|
|
37
|
-
|
|
262
|
+
function getOAuthUrlsForEnvironment(environment, backendForTier, issuerOverridden = false) {
|
|
263
|
+
const known = environment in Environments;
|
|
264
|
+
const effective = known ? environment : 'sandbox';
|
|
265
|
+
const envConfig = Environments[effective];
|
|
266
|
+
const backend = backendForTier || envConfig.backend;
|
|
267
|
+
const tier = resolveOAuthTier(effective, backend);
|
|
268
|
+
if (effective === 'custom' && !tier && !tierlessWarned) {
|
|
269
|
+
// Omitting beats guessing, but never silently: the document is served 200 and cached for an
|
|
270
|
+
// hour, and the operator's first evidence would otherwise be a user on the wrong consent screen.
|
|
271
|
+
tierlessWarned = true;
|
|
272
|
+
console.warn(`[Nevermined] Could not derive the API tier from backend host '${hostOf(backend)}' — ` +
|
|
273
|
+
`authorization_endpoint will be advertised without ?${OAUTH_TIER_PARAM}=. Set ` +
|
|
274
|
+
`oauthUrls.authorizationUri to the Nevermined web app URL including ` +
|
|
275
|
+
`?${OAUTH_TIER_PARAM}=sandbox|live for this deployment.`);
|
|
276
|
+
}
|
|
277
|
+
if (effective !== 'custom' && backendForTier && !crossTierWarned) {
|
|
278
|
+
const overrideTier = tierFromHost(backendForTier);
|
|
279
|
+
if (overrideTier && overrideTier !== tier) {
|
|
280
|
+
crossTierWarned = true;
|
|
281
|
+
console.warn(`[Nevermined] oauthUrls.tokenUri points at the ${overrideTier} API ` +
|
|
282
|
+
`('${hostOf(backendForTier)}') but the environment is '${effective}' (${tier}); ` +
|
|
283
|
+
`authorization_endpoint keeps ?${OAUTH_TIER_PARAM}=${tier} from the environment, so the ` +
|
|
284
|
+
`consent screen and the token endpoint would sit on different tiers. Use the same tier ` +
|
|
285
|
+
`for both.`);
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
return buildOAuthUrls(envConfig.frontend, envConfig.backend, tier, issuerFor(effective, backend, envConfig.backend, issuerOverridden));
|
|
38
289
|
}
|
|
39
290
|
/**
|
|
40
291
|
* Default scopes supported by Nevermined MCP servers.
|
|
@@ -55,8 +306,63 @@ const DEFAULT_SCOPES = [
|
|
|
55
306
|
* @returns Complete OAuth URLs configuration
|
|
56
307
|
*/
|
|
57
308
|
export function getOAuthUrls(environment, overrides) {
|
|
58
|
-
|
|
59
|
-
|
|
309
|
+
// An overridden `authorizationUri` is passed through verbatim — the SDK cannot know whether it is
|
|
310
|
+
// the Nevermined webapp or a foreign AS, so an operator who points it at the webapp includes
|
|
311
|
+
// `?network=` themselves (documented on `OAuthUrls.authorizationUri`).
|
|
312
|
+
//
|
|
313
|
+
// Only a NON-EMPTY string overrides. `{ issuer: process.env.OAUTH_ISSUER }` with the variable unset
|
|
314
|
+
// type-checks (exactOptionalPropertyTypes is off) and used to spread `undefined` over the computed
|
|
315
|
+
// value, so `res.json` served the AS and OIDC documents WITHOUT their required `issuer` — for an
|
|
316
|
+
// hour, under `Cache-Control: public` (payments#464 review). Same for `''`.
|
|
317
|
+
const clean = Object.fromEntries(Object.entries(overrides ?? {}).filter(([, v]) => typeof v === 'string' && v.length > 0));
|
|
318
|
+
const baseUrls = getOAuthUrlsForEnvironment(environment, clean.tokenUri, clean.issuer !== undefined);
|
|
319
|
+
if (environment !== 'custom' && clean.issuer !== undefined && clean.issuer !== baseUrls.issuer) {
|
|
320
|
+
// A NAMED environment's issuer is not configurable in fact: the web app returns the canonical
|
|
321
|
+
// origin as RFC 9207 `iss` from its own fixed per-tier config, and these documents advertise
|
|
322
|
+
// `authorization_response_iss_parameter_supported`, so a client compares `iss` with THIS value
|
|
323
|
+
// and rejects every code. The override is still published — the operator's word is honoured —
|
|
324
|
+
// but the failure must not arrive as an unexplained client-side rejection (#466 review). Keyed
|
|
325
|
+
// on the value, like the other issuer warnings, so a corrected typo re-alerts.
|
|
326
|
+
warnIssuerOnce(`override:${clean.issuer}`, `[Nevermined] oauthUrls.issuer '${clean.issuer}' differs from the canonical issuer of the ` +
|
|
327
|
+
`'${environment}' environment, '${baseUrls.issuer}' — the iss the Nevermined consent page ` +
|
|
328
|
+
`returns on every authorization response. An RFC 9207 client compares the two and will ` +
|
|
329
|
+
`reject every authorization code. Remove oauthUrls.issuer, or set it to '${baseUrls.issuer}'.`);
|
|
330
|
+
}
|
|
331
|
+
return { ...baseUrls, ...clean };
|
|
332
|
+
}
|
|
333
|
+
/**
|
|
334
|
+
* RFC 9207 §3: an authorization server that returns the `iss` parameter on every authorization
|
|
335
|
+
* response advertises `authorization_response_iss_parameter_supported: true`; §2.4 then has a client
|
|
336
|
+
* REJECT any response lacking `iss`. An omitted flag DEFAULTS to `false` (§3), so the SDK publishes it
|
|
337
|
+
* only where it is true and omits it everywhere else — never an explicit `false`, which would say the
|
|
338
|
+
* same thing louder. True where: the consent page is the Nevermined web app, which has returned `iss`
|
|
339
|
+
* (= the canonical API origin these documents publish as `issuer`) on every response since
|
|
340
|
+
* nvm-monorepo#3532 — the API's own document advertises the same flag. That is every NAMED
|
|
341
|
+
* environment (the decision, payments#466). Omitted for `custom` — its frontend may be an older or
|
|
342
|
+
* self-hosted web app, and this SDK cannot tell (a `custom` server on a Nevermined backend AND
|
|
343
|
+
* frontend is deliberately still omitted: the decision drew the line at the environment name, not at
|
|
344
|
+
* a host guess) — and whenever `oauthUrls.authorizationUri` is overridden, since the consent page is
|
|
345
|
+
* then an AS this SDK cannot vouch for, even when the value happens to point at the Nevermined web
|
|
346
|
+
* app. The override predicate is the same "non-empty string" rule `getOAuthUrls` applies.
|
|
347
|
+
*
|
|
348
|
+
* Two limits of the omission, so nobody widens or narrows it for the wrong reason (#466 review):
|
|
349
|
+
* - It is a TRADE, not a neutral default. §2.4's other half has a client SHOULD-discard a response
|
|
350
|
+
* that carries `iss` from a server that did not advertise — exactly the state an override that
|
|
351
|
+
* still points at the Nevermined web app (which returns `iss` unconditionally) lands in. Omitting
|
|
352
|
+
* swaps the MUST-reject for the SHOULD-discard; the operator docs say so.
|
|
353
|
+
* - It reaches only a client that discovers DIRECTLY against this server. One that follows the
|
|
354
|
+
* protected-resource document's `authorization_servers` reads the Nevermined API's own metadata,
|
|
355
|
+
* which advertises the flag unconditionally (`apps/api/src/well-known/well-known.service.ts`) —
|
|
356
|
+
* so a `custom` deployment on a Nevermined backend with an older frontend is not shielded on
|
|
357
|
+
* that route, whatever this document says.
|
|
358
|
+
*/
|
|
359
|
+
function issParameterSupport(environment, overrides) {
|
|
360
|
+
const consentOverridden = typeof overrides?.authorizationUri === 'string' && overrides.authorizationUri.length > 0;
|
|
361
|
+
// An unknown environment name is served the sandbox documents by `getOAuthUrls`, and is not
|
|
362
|
+
// `custom` — so the only name that omits is `custom` itself.
|
|
363
|
+
return environment !== 'custom' && !consentOverridden
|
|
364
|
+
? { authorization_response_iss_parameter_supported: true }
|
|
365
|
+
: {};
|
|
60
366
|
}
|
|
61
367
|
/**
|
|
62
368
|
* Build Protected Resource Metadata (RFC 9728).
|
|
@@ -88,29 +394,16 @@ export function buildProtectedResourceMetadata(config) {
|
|
|
88
394
|
/**
|
|
89
395
|
* Resolve the authorization-server identifier for `authorization_servers`.
|
|
90
396
|
*
|
|
91
|
-
* RFC 9728 §2
|
|
92
|
-
*
|
|
93
|
-
*
|
|
94
|
-
*
|
|
95
|
-
*
|
|
96
|
-
*
|
|
97
|
-
*
|
|
98
|
-
* The backend origin is derived from `tokenUri` (`${backend}/oauth/token`), which
|
|
99
|
-
* respects any `config.oauthUrls.tokenUri` override.
|
|
397
|
+
* RFC 9728 §2 defines each entry as an AS **issuer identifier**, so it is, by construction, the
|
|
398
|
+
* `issuer` this server's own AS document publishes — one derivation (`issuerFor` via `getOAuthUrls`),
|
|
399
|
+
* so the two can never disagree: not on a `tokenUri` override, not on an `issuer` override (a
|
|
400
|
+
* foreign AS named there is then also where clients are sent), not on malformed input. It used to be
|
|
401
|
+
* derived separately from `tokenUri` with its own fallback, which put `issuer` and
|
|
402
|
+
* `authorization_servers` on different values for a malformed override (payments#464 review).
|
|
403
|
+
* It is NOT `config.baseUrl` — that is this MCP server, the protected *resource*.
|
|
100
404
|
*/
|
|
101
405
|
function resolveAuthorizationServer(config) {
|
|
102
|
-
|
|
103
|
-
const envTokenUri = getOAuthUrls(config.environment).tokenUri;
|
|
104
|
-
// Guard both a falsy `{ tokenUri: undefined }` override (slips through the
|
|
105
|
-
// `{...baseUrls, ...overrides}` spread — exactOptionalPropertyTypes is off) AND
|
|
106
|
-
// a malformed non-falsy one — fall back to the environment default rather than
|
|
107
|
-
// crash the metadata endpoint with `new URL(...)`.
|
|
108
|
-
try {
|
|
109
|
-
return new URL(tokenUri || envTokenUri).origin;
|
|
110
|
-
}
|
|
111
|
-
catch {
|
|
112
|
-
return new URL(envTokenUri).origin;
|
|
113
|
-
}
|
|
406
|
+
return getOAuthUrls(config.environment, config.oauthUrls).issuer;
|
|
114
407
|
}
|
|
115
408
|
/**
|
|
116
409
|
* Build MCP-specific Protected Resource Metadata.
|
|
@@ -133,8 +426,8 @@ export function buildMcpProtectedResourceMetadata(config) {
|
|
|
133
426
|
const scopes = config.scopes || [...DEFAULT_SCOPES];
|
|
134
427
|
return {
|
|
135
428
|
resource: `${config.baseUrl}/mcp`,
|
|
136
|
-
// See resolveAuthorizationServer: the AS is the
|
|
137
|
-
//
|
|
429
|
+
// See resolveAuthorizationServer: the AS is the issuer this server's own AS document
|
|
430
|
+
// publishes (the backend API origin), never this MCP server (baseUrl).
|
|
138
431
|
authorization_servers: [resolveAuthorizationServer(config)],
|
|
139
432
|
scopes_supported: scopes,
|
|
140
433
|
scopes_required: scopes,
|
|
@@ -177,6 +470,7 @@ export function buildAuthorizationServerMetadata(config) {
|
|
|
177
470
|
scopes_supported: scopes,
|
|
178
471
|
token_endpoint_auth_methods_supported: ['client_secret_post'],
|
|
179
472
|
subject_types_supported: ['public'],
|
|
473
|
+
...issParameterSupport(config.environment, config.oauthUrls),
|
|
180
474
|
};
|
|
181
475
|
}
|
|
182
476
|
/**
|
|
@@ -214,6 +508,7 @@ export function buildOidcConfiguration(config) {
|
|
|
214
508
|
id_token_signing_alg_values_supported: ['RS256', 'HS256'],
|
|
215
509
|
scopes_supported: allScopes,
|
|
216
510
|
claims_supported: ['sub', 'iss', 'aud', 'exp', 'iat', 'name', 'email'],
|
|
511
|
+
...issParameterSupport(config.environment, config.oauthUrls),
|
|
217
512
|
};
|
|
218
513
|
}
|
|
219
514
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"oauth-metadata.js","sourceRoot":"","sources":["../../../src/mcp/http/oauth-metadata.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Pure functions to generate OAuth 2.1 metadata responses.\n * These generators produce the JSON payloads for OAuth discovery endpoints\n * without any framework dependencies, making them reusable across different HTTP servers.\n */\nimport { Environments, type EnvironmentName } from '../../environments.js'\nimport type {\n OAuthUrls,\n OAuthConfig,\n ProtectedResourceMetadata,\n McpProtectedResourceMetadata,\n AuthorizationServerMetadata,\n OidcConfiguration,\n} from '../types/http.types.js'\n\n/**\n * Build OAuth URLs from frontend and backend URLs.\n * - issuer and authorizationUri use the frontend (user-facing)\n * - tokenUri, jwksUri, userinfoUri use the backend (API)\n *\n * @param frontendUrl - The frontend URL (e.g., https://nevermined.app)\n * @param backendUrl - The backend URL (e.g., https://api.sandbox.nevermined.app)\n * @returns OAuth URLs configuration\n */\nfunction buildOAuthUrls(frontendUrl: string, backendUrl: string): OAuthUrls {\n // Remove trailing slashes\n const frontend = frontendUrl.replace(/\\/$/, '')\n const backend = backendUrl.replace(/\\/$/, '')\n\n return {\n issuer: frontend,\n authorizationUri: `${frontend}/oauth/authorize`,\n tokenUri: `${backend}/oauth/token`,\n jwksUri: `${backend}/.well-known/jwks.json`,\n userinfoUri: `${backend}/oauth/userinfo`,\n }\n}\n\n/**\n * Get OAuth URLs for an environment.\n * Uses frontend and backend URLs from Environments configuration.\n *\n * @param environment - The Nevermined environment name\n * @returns OAuth URLs configuration\n */\nfunction getOAuthUrlsForEnvironment(environment: EnvironmentName): OAuthUrls {\n const envConfig = Environments[environment] || Environments.sandbox\n return buildOAuthUrls(envConfig.frontend, envConfig.backend)\n}\n\n/**\n * Default scopes supported by Nevermined MCP servers.\n */\nconst DEFAULT_SCOPES: readonly string[] = [\n 'openid',\n 'profile',\n 'credits',\n 'mcp:read',\n 'mcp:write',\n 'mcp:tools',\n]\n\n/**\n * Get OAuth URLs for a given environment with optional overrides.\n *\n * @param environment - The Nevermined environment name\n * @param overrides - Optional partial overrides for specific URLs\n * @returns Complete OAuth URLs configuration\n */\nexport function getOAuthUrls(\n environment: EnvironmentName,\n overrides?: Partial<OAuthUrls>,\n): OAuthUrls {\n const baseUrls = getOAuthUrlsForEnvironment(environment)\n return { ...baseUrls, ...overrides }\n}\n\n/**\n * Build Protected Resource Metadata (RFC 9728).\n * This metadata tells OAuth clients about the protected resource.\n *\n * @param config - OAuth configuration\n * @returns Protected Resource Metadata response object\n *\n * @example\n * ```typescript\n * const metadata = buildProtectedResourceMetadata({\n * baseUrl: 'http://localhost:5001',\n * agentId: 'agent_123',\n * environment: 'staging_sandbox'\n * })\n * // Returns: { resource: 'http://localhost:5001', authorization_servers: [...], ... }\n * ```\n */\nexport function buildProtectedResourceMetadata(config: OAuthConfig): ProtectedResourceMetadata {\n const scopes = config.scopes || [...DEFAULT_SCOPES]\n\n return {\n resource: config.baseUrl,\n authorization_servers: [resolveAuthorizationServer(config)],\n scopes_supported: scopes,\n bearer_methods_supported: ['header'],\n resource_documentation: `${config.baseUrl}/`,\n }\n}\n\n/**\n * Resolve the authorization-server identifier for `authorization_servers`.\n *\n * RFC 9728 §2 requires each entry to be an AS issuer identifier — a URL from\n * which `/.well-known/oauth-authorization-server` (RFC 8414) actually resolves.\n * For Nevermined that is the **backend** API origin (which serves the AS\n * metadata and whose own published `issuer` is the backend URL), NOT:\n * - `config.baseUrl` — that is this MCP server, the protected *resource*; and\n * - `OAuthUrls.issuer` — that is the *frontend* (a client-routed SPA that 200s\n * on every path, so an RFC 8414 fetch there silently returns HTML).\n * The backend origin is derived from `tokenUri` (`${backend}/oauth/token`), which\n * respects any `config.oauthUrls.tokenUri` override.\n */\nfunction resolveAuthorizationServer(config: OAuthConfig): string {\n const { tokenUri } = getOAuthUrls(config.environment, config.oauthUrls)\n const envTokenUri = getOAuthUrls(config.environment).tokenUri\n // Guard both a falsy `{ tokenUri: undefined }` override (slips through the\n // `{...baseUrls, ...overrides}` spread — exactOptionalPropertyTypes is off) AND\n // a malformed non-falsy one — fall back to the environment default rather than\n // crash the metadata endpoint with `new URL(...)`.\n try {\n return new URL(tokenUri || envTokenUri).origin\n } catch {\n return new URL(envTokenUri).origin\n }\n}\n\n/**\n * Build MCP-specific Protected Resource Metadata.\n * Extends the base metadata with MCP capabilities information.\n *\n * @param config - OAuth configuration\n * @returns MCP Protected Resource Metadata response object\n *\n * @example\n * ```typescript\n * const metadata = buildMcpProtectedResourceMetadata({\n * baseUrl: 'http://localhost:5001',\n * agentId: 'agent_123',\n * environment: 'staging_sandbox',\n * tools: ['hello_world', 'weather']\n * })\n * ```\n */\nexport function buildMcpProtectedResourceMetadata(\n config: OAuthConfig,\n): McpProtectedResourceMetadata {\n const scopes = config.scopes || [...DEFAULT_SCOPES]\n\n return {\n resource: `${config.baseUrl}/mcp`,\n // See resolveAuthorizationServer: the AS is the backend API origin, not this\n // MCP server (baseUrl) nor the frontend SPA (OAuthUrls.issuer).\n authorization_servers: [resolveAuthorizationServer(config)],\n scopes_supported: scopes,\n scopes_required: scopes,\n bearer_methods_supported: ['header'],\n resource_documentation: `${config.baseUrl}/`,\n mcp_capabilities: {\n tools: config.tools || [],\n protocol_version: config.protocolVersion || '2024-11-05',\n },\n }\n}\n\n/**\n * Build OAuth Authorization Server Metadata (RFC 8414).\n * This metadata describes the OAuth authorization server configuration.\n *\n * @param config - OAuth configuration\n * @returns Authorization Server Metadata response object\n *\n * @example\n * ```typescript\n * const metadata = buildAuthorizationServerMetadata({\n * baseUrl: 'http://localhost:5001',\n * agentId: 'agent_123',\n * environment: 'staging_sandbox'\n * })\n * ```\n */\nexport function buildAuthorizationServerMetadata(config: OAuthConfig): AuthorizationServerMetadata {\n const oauthUrls = getOAuthUrls(config.environment, config.oauthUrls)\n const scopes = config.scopes || [...DEFAULT_SCOPES]\n\n return {\n issuer: oauthUrls.issuer,\n authorization_endpoint: oauthUrls.authorizationUri,\n token_endpoint: oauthUrls.tokenUri,\n registration_endpoint: `${config.baseUrl}/register`,\n jwks_uri: oauthUrls.jwksUri,\n response_types_supported: ['code'],\n grant_types_supported: ['authorization_code', 'refresh_token'],\n code_challenge_methods_supported: ['S256'],\n scopes_supported: scopes,\n token_endpoint_auth_methods_supported: ['client_secret_post'],\n subject_types_supported: ['public'],\n }\n}\n\n/**\n * Build OpenID Connect Discovery Metadata.\n * Provides OIDC-compatible configuration for clients that expect OpenID Connect.\n *\n * @param config - OAuth configuration\n * @returns OIDC Configuration response object\n *\n * @example\n * ```typescript\n * const metadata = buildOidcConfiguration({\n * baseUrl: 'http://localhost:5001',\n * agentId: 'agent_123',\n * environment: 'staging_sandbox'\n * })\n * ```\n */\nexport function buildOidcConfiguration(config: OAuthConfig): OidcConfiguration {\n const oauthUrls = getOAuthUrls(config.environment, config.oauthUrls)\n const scopes = config.scopes || [...DEFAULT_SCOPES]\n const allScopes = scopes.includes('openid') ? scopes : ['openid', ...scopes]\n\n return {\n issuer: oauthUrls.issuer,\n authorization_endpoint: oauthUrls.authorizationUri,\n token_endpoint: oauthUrls.tokenUri,\n jwks_uri: oauthUrls.jwksUri,\n userinfo_endpoint: oauthUrls.userinfoUri,\n registration_endpoint: `${config.baseUrl}/register`,\n response_types_supported: ['code'],\n grant_types_supported: ['authorization_code', 'refresh_token'],\n code_challenge_methods_supported: ['S256'],\n token_endpoint_auth_methods_supported: ['none', 'client_secret_post'],\n subject_types_supported: ['public'],\n id_token_signing_alg_values_supported: ['RS256', 'HS256'],\n scopes_supported: allScopes,\n claims_supported: ['sub', 'iss', 'aud', 'exp', 'iat', 'name', 'email'],\n }\n}\n\n/**\n * Build server info response for the root endpoint.\n *\n * @param config - OAuth configuration\n * @param options - Additional options for the server info\n * @returns Server info response object\n */\nexport function buildServerInfoResponse(\n config: OAuthConfig,\n options?: {\n version?: string\n description?: string\n },\n): {\n name: string\n version: string\n description: string\n endpoints: Record<string, string>\n oauth: Record<string, any>\n tools: string[]\n resources: string[]\n prompts: string[]\n} {\n const oauthUrls = getOAuthUrls(config.environment, config.oauthUrls)\n const scopes = config.scopes || [...DEFAULT_SCOPES]\n\n return {\n name: config.serverName || 'MCP Server',\n version: options?.version || '1.0.0',\n description:\n options?.description || 'MCP server with Nevermined OAuth integration via Streamable HTTP',\n endpoints: {\n mcp: `${config.baseUrl}/mcp`,\n health: `${config.baseUrl}/health`,\n register: `${config.baseUrl}/register`,\n },\n oauth: {\n authorization_server_metadata: `${config.baseUrl}/.well-known/oauth-authorization-server`,\n protected_resource_metadata: `${config.baseUrl}/.well-known/oauth-protected-resource`,\n openid_configuration: `${config.baseUrl}/.well-known/openid-configuration`,\n authorization_endpoint: oauthUrls.authorizationUri,\n token_endpoint: oauthUrls.tokenUri,\n jwks_uri: oauthUrls.jwksUri,\n registration_endpoint: `${config.baseUrl}/register`,\n // agentId is optional under the plan-centric model; omit client_id when absent.\n ...(config.agentId ? { client_id: config.agentId } : {}),\n scopes: scopes,\n },\n tools: config.tools || [],\n resources: config.resources || [],\n prompts: config.prompts || [],\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"oauth-metadata.js","sourceRoot":"","sources":["../../../src/mcp/http/oauth-metadata.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Pure functions to generate OAuth 2.1 metadata responses.\n * These generators produce the JSON payloads for OAuth discovery endpoints\n * without any framework dependencies, making them reusable across different HTTP servers.\n */\nimport { Environments, type EnvironmentName } from '../../environments.js'\nimport type {\n OAuthUrls,\n OAuthConfig,\n ProtectedResourceMetadata,\n McpProtectedResourceMetadata,\n AuthorizationServerMetadata,\n OidcConfiguration,\n} from '../types/http.types.js'\n\n/**\n * The query parameter that tells the Nevermined web app WHICH API tier an OAuth ceremony belongs\n * to, and its two values. Each tier (sandbox / live) is its own authorization server, but ONE web\n * app serves the consent screens for both and boots on whatever tier the user's browser last chose\n * — Live by default. A bare `https://nevermined.app/oauth/authorize` therefore sends a sandbox MCP\n * server's users to the LIVE consent screen, where the connector is not registered (\"Connector not\n * authorized\"). The tier is stated on the URL instead; RFC 6749 §3.1 obliges clients to retain the\n * query component when they add their own parameters. Same name and values as the Nevermined API's\n * own RFC 8414 document and the embed widget (nvm-monorepo#3430 / #1787).\n */\nexport const OAUTH_TIER_PARAM = 'network'\nexport const OAUTH_TIERS = ['sandbox', 'live'] as const\nexport type OAuthTier = (typeof OAUTH_TIERS)[number]\n\n/**\n * The API tier an environment belongs to. The four named environments map directly. `custom` is\n * derived from the host of the backend it will publish as `token_endpoint`: a Nevermined API host has\n * an `api` label immediately followed by the tier label — `api.sandbox.nevermined.app`,\n * `<slug>.api.live.nevermined.app` (branded per-org subdomains), `mcp.api.sandbox.nevermined.dev` —\n * so that label pair is what is matched, never a bare `sandbox` anywhere in the host. When the host\n * cannot be classified (a `localhost` stack, a proxy/CNAME in front of the API) the tier is\n * **omitted**, not guessed: the URL stays the pre-#3430 bare one, and the operator sets\n * `oauthUrls.authorizationUri` (with `?network=` on it) to say which tier that deployment is —\n * `getOAuthUrlsForEnvironment` warns once when that happens, so the degradation is never silent.\n *\n * ⚠️ This is not the only classifier of a `custom` backend for the `network` value — the CLI's\n * `resolveEmbedNetwork` (`cli/src/utils/widget-redirect-flow.ts`) and nvm-monorepo's\n * `deriveEmbedNetwork` (`apps/mcp/src/config.ts`) classify the same input. All three now apply THIS\n * rule — the `api.<tier>` label pair, never guessing (the CLI ports it verbatim, payments#456; the\n * monorepo via the shared `oauthTierFromHostname`, nvm-monorepo#3638). Keep them in sync; do not\n * derive a fourth rule here.\n */\nexport function resolveOAuthTier(\n environment: EnvironmentName,\n backendUrl: string,\n): OAuthTier | undefined {\n switch (environment) {\n case 'sandbox':\n case 'staging_sandbox':\n return 'sandbox'\n case 'live':\n case 'staging_live':\n return 'live'\n default:\n return tierFromHost(backendUrl)\n }\n}\n\n/**\n * The `api.<tier>` label-pair match behind {@link resolveOAuthTier}'s `custom` branch: the FIRST\n * `api` label that a tier label FOLLOWS — not the first `api` label, full stop. The two differ on\n * one served shape: an org slugged `api` (legal today) gets the branded host\n * `api.api.live.nevermined.app`, which `labels[indexOf('api') + 1]` read as `api` and refused.\n * Same rule as nvm-monorepo's shared `oauthTierFromHostname` (`@nevermined-io/commons`), so the\n * SDK, the Commerce MCP and the API classify a host identically (payments#468).\n */\nfunction tierFromHost(url: string): OAuthTier | undefined {\n let labels: string[]\n try {\n // WHATWG `hostname` is lowercased and carries no port/credentials/path.\n labels = new URL(url).hostname.split('.')\n } catch {\n return undefined\n }\n for (let i = 0; i + 1 < labels.length; i++) {\n if (labels[i] === 'api' && (OAUTH_TIERS as readonly string[]).includes(labels[i + 1])) {\n return labels[i + 1] as OAuthTier\n }\n }\n return undefined\n}\n\n/** Best-effort host for a warning line; never throws on a malformed URL. */\nfunction hostOf(url: string): string {\n try {\n return new URL(url).host\n } catch {\n return url\n }\n}\n\n// Warn-once flags, module-level like `environmentOptionDeprecationWarned` in `base-payments.ts`:\n// discovery documents are rebuilt per request, and a warning per request is noise nobody reads.\nlet tierlessWarned = false\nlet crossTierWarned = false\n\n/**\n * Append `?network=<tier>` to the authorize URL. Goes through the URL API so the result is a\n * canonical absolute URL with one query string; a frontend that is not an absolute URL (a relative\n * `NVM_FRONTEND_URL` such as `/webapp`) cannot be parsed, and falls back to plain concatenation —\n * the same shape the tier-less URL always had for that misconfiguration.\n */\nfunction withTierParam(authorizeUrl: string, tier: OAuthTier | undefined): string {\n if (!tier) return authorizeUrl\n try {\n const url = new URL(authorizeUrl)\n url.searchParams.set(OAUTH_TIER_PARAM, tier)\n return url.toString()\n } catch {\n return `${authorizeUrl}${authorizeUrl.includes('?') ? '&' : '?'}${OAUTH_TIER_PARAM}=${tier}`\n }\n}\n\n/**\n * The ORIGIN of a URL — `new URL(u).origin` — or `undefined` when the string does not parse or\n * parses to an opaque origin: `new URL('localhost:3001')` succeeds (scheme `localhost:`) with\n * `.origin === 'null'`, which can never be an RFC 8414 issuer.\n */\nfunction originOf(url: string): string | undefined {\n try {\n const origin = new URL(url).origin\n return origin === 'null' ? undefined : origin\n } catch {\n return undefined\n }\n}\n\n/**\n * The canonical Nevermined API origin a backend host stands for, or `undefined` for a host that\n * is not a Nevermined API. `<slug>.api.live.nevermined.app` (a branded per-org subdomain) and\n * `mcp.api.sandbox.nevermined.dev` both serve the same API as `api.<tier>.nevermined.<tld>` — and\n * that canonical origin is what the two parties an issuer must agree with actually use: the API's\n * own RFC 8414 document anchors `issuer` on `API_HOST`, never the request host, and the web app\n * returns RFC 9207 `iss` from its fixed per-tier config. Publishing the branded origin as `issuer`\n * would fail every RFC 9207 client's simple-string compare (payments#464 review). The suffix\n * requirement is deliberate: it derives a HOST, and only a Nevermined host has a canonical form.\n */\nfunction canonicalNeverminedOrigin(backendUrl: string): string | undefined {\n const tier = tierFromHost(backendUrl)\n if (!tier) return undefined\n let hostname: string\n try {\n // A trailing-dot FQDN (`api.sandbox.nevermined.app.`) is the same host to DNS; keep the suffix\n // checks from missing it and republishing a one-byte-off issuer.\n hostname = new URL(backendUrl).hostname.replace(/\\.$/, '')\n } catch {\n return undefined\n }\n let environment: EnvironmentName | undefined\n if (hostname.endsWith('.nevermined.app')) environment = tier\n else if (hostname.endsWith('.nevermined.dev'))\n environment = tier === 'live' ? 'staging_live' : 'staging_sandbox'\n return environment ? originOf(Environments[environment].backend) : undefined\n}\n\n// Warned once per DISTINCT value (a changed typo re-alerts), and never when the operator has\n// already set `oauthUrls.issuer` — the remedy the warning names.\nconst issuerWarned = new Set<string>()\n\nfunction isLoopback(origin: string): boolean {\n try {\n const host = new URL(origin).hostname\n return host === 'localhost' || host === '127.0.0.1' || host === '[::1]'\n } catch {\n return false\n }\n}\n\nfunction warnIssuerOnce(key: string, message: string): void {\n if (issuerWarned.has(key)) return\n issuerWarned.add(key)\n console.warn(message)\n}\n\n/**\n * The RFC 8414 issuer identifier of the authorization server a document describes.\n *\n * It is the ORIGIN of the Nevermined API the document points at — the value the API's own\n * document publishes and the web app returns as RFC 9207 `iss` on every authorization response,\n * which an RFC 9207 client compares with the discovered `issuer` by SIMPLE STRING comparison and\n * rejects on any difference. So it has to be the canonical origin, byte for byte:\n * - a NAMED environment is that identity — its canonical backend origin, whatever `tokenUri`\n * override sits in front of it (a same-tier proxy is still the same authorization server; a\n * cross-tier override is a misconfiguration `getOAuthUrlsForEnvironment` already warns about);\n * - `custom` follows the backend the document PUBLISHES (a `tokenUri` override, else its own):\n * the canonical Nevermined origin when that host classifies, else the host's own origin, else —\n * unparsable or opaque — the environment backend's origin, else the raw string minus its\n * trailing slash, warned once. A metadata endpoint never throws.\n */\nfunction issuerFor(\n effective: EnvironmentName,\n publishedBackend: string,\n envBackend: string,\n issuerOverridden: boolean,\n): string {\n if (effective !== 'custom') {\n // Every named environment's backend is a canonical absolute URL (`src/environments.ts`).\n return originOf(envBackend) ?? envBackend.replace(/\\/$/, '')\n }\n const canonical = canonicalNeverminedOrigin(publishedBackend)\n if (canonical) return canonical\n const own = originOf(publishedBackend) ?? originOf(envBackend)\n if (own) {\n // The right value for a genuinely foreign API — and the WRONG one for a proxy/CNAME in front\n // of the real Nevermined API (`https://api.live.example.com` → the web app still returns\n // `iss = https://api.live.nevermined.app`, so every RFC 9207 client rejects the code). The SDK\n // cannot tell the two apart, so it says what it derived and names the remedy (#464 review).\n // A loopback host is a local stack, not a proxy for the real API, and already gets the tier\n // warning — no second line there.\n if (!issuerOverridden && !isLoopback(own)) {\n warnIssuerOnce(\n own,\n `[Nevermined] OAuth issuer derived from backend host '${hostOf(publishedBackend)}' as ` +\n `'${own}'. If that host is a proxy or gateway in front of a Nevermined API rather than ` +\n `the API itself, set oauthUrls.issuer (and oauthUrls.tokenUri) to that API's real origin — ` +\n `otherwise the issuer will not match the iss the authorization server returns.`,\n )\n }\n return own\n }\n const raw = publishedBackend.replace(/\\/$/, '')\n if (!issuerOverridden) {\n warnIssuerOnce(\n raw,\n `[Nevermined] Could not derive an OAuth issuer from backend '${publishedBackend}' — ` +\n `publishing '${raw}'. Set oauthUrls.issuer (and oauthUrls.tokenUri) to the API origin ` +\n `of this deployment's tier.`,\n )\n }\n return raw\n}\n\n/**\n * Build OAuth URLs from frontend and backend URLs.\n * - authorizationUri uses the frontend (user-facing consent page) and carries the tier\n * - issuer, tokenUri, jwksUri, userinfoUri use the backend (the API is the authorization server)\n *\n * `issuer` used to be the FRONTEND origin — identical for both tiers, since one web app serves both\n * consent screens — while `authorization_servers` (RFC 9728), `token_endpoint` and the API's own\n * RFC 8414 document all named the backend. That was a tier-blind identifier, and once the web app\n * started returning RFC 9207 `iss` = the API origin (nvm-monorepo#3532) it made every RFC 9207\n * client that discovers via THIS server's well-known reject its authorization responses. payments#464.\n *\n * @param frontendUrl - The frontend URL (e.g., https://nevermined.app)\n * @param backendUrl - The backend URL (e.g., https://api.sandbox.nevermined.app)\n * @param tier - The API tier to stamp on the authorize URL (see {@link resolveOAuthTier})\n * @param issuer - The issuer identifier (see {@link issuerFor})\n * @returns OAuth URLs configuration\n */\nfunction buildOAuthUrls(\n frontendUrl: string,\n backendUrl: string,\n tier: OAuthTier | undefined,\n issuer: string,\n): OAuthUrls {\n // Remove trailing slashes\n const frontend = frontendUrl.replace(/\\/$/, '')\n const backend = backendUrl.replace(/\\/$/, '')\n\n return {\n issuer,\n authorizationUri: withTierParam(`${frontend}/oauth/authorize`, tier),\n tokenUri: `${backend}/oauth/token`,\n jwksUri: `${backend}/.well-known/jwks.json`,\n userinfoUri: `${backend}/oauth/userinfo`,\n }\n}\n\n/**\n * Get OAuth URLs for an environment.\n * Uses frontend and backend URLs from Environments configuration. An unknown environment name (a\n * JS caller / cast — `EnvironmentName` is closed) falls back to `sandbox`, as it always did; the\n * fallback is now internally consistent (a sandbox `token_endpoint` AND a sandbox-tagged authorize).\n *\n * @param environment - The Nevermined environment name\n * @param backendForTier - The backend the document will actually publish as `token_endpoint` —\n * the environment's, or an `oauthUrls.tokenUri` override. The tier follows THAT under `custom`,\n * exactly as `resolveAuthorizationServer` derives the AS origin from it: a `custom` server whose\n * `tokenUri` is overridden to `api.sandbox.…` must not publish a sandbox token endpoint next to a\n * tier-blind authorize URL (payments#455 review). Under a NAMED environment the environment's tier\n * takes precedence over the override — deliberately: a same-tier proxy (`sandbox` +\n * `tokenUri: https://gw.corp.com/…`) classifies to nothing and must keep the tier it has. When the\n * override's host classifies to the OTHER tier the combination is always a misconfiguration (the\n * consent screen on one tier, the token endpoint on the other, and the code exchange failing as a\n * \"bad or expired code\"), so it is warned once rather than silently honoured. The ISSUER of a\n * named environment never follows the override at all — see {@link issuerFor}.\n * @returns OAuth URLs configuration\n */\nfunction getOAuthUrlsForEnvironment(\n environment: EnvironmentName,\n backendForTier?: string,\n issuerOverridden = false,\n): OAuthUrls {\n const known = environment in Environments\n const effective: EnvironmentName = known ? environment : 'sandbox'\n const envConfig = Environments[effective]\n const backend = backendForTier || envConfig.backend\n const tier = resolveOAuthTier(effective, backend)\n\n if (effective === 'custom' && !tier && !tierlessWarned) {\n // Omitting beats guessing, but never silently: the document is served 200 and cached for an\n // hour, and the operator's first evidence would otherwise be a user on the wrong consent screen.\n tierlessWarned = true\n console.warn(\n `[Nevermined] Could not derive the API tier from backend host '${hostOf(backend)}' — ` +\n `authorization_endpoint will be advertised without ?${OAUTH_TIER_PARAM}=. Set ` +\n `oauthUrls.authorizationUri to the Nevermined web app URL including ` +\n `?${OAUTH_TIER_PARAM}=sandbox|live for this deployment.`,\n )\n }\n if (effective !== 'custom' && backendForTier && !crossTierWarned) {\n const overrideTier = tierFromHost(backendForTier)\n if (overrideTier && overrideTier !== tier) {\n crossTierWarned = true\n console.warn(\n `[Nevermined] oauthUrls.tokenUri points at the ${overrideTier} API ` +\n `('${hostOf(backendForTier)}') but the environment is '${effective}' (${tier}); ` +\n `authorization_endpoint keeps ?${OAUTH_TIER_PARAM}=${tier} from the environment, so the ` +\n `consent screen and the token endpoint would sit on different tiers. Use the same tier ` +\n `for both.`,\n )\n }\n }\n\n return buildOAuthUrls(\n envConfig.frontend,\n envConfig.backend,\n tier,\n issuerFor(effective, backend, envConfig.backend, issuerOverridden),\n )\n}\n\n/**\n * Default scopes supported by Nevermined MCP servers.\n */\nconst DEFAULT_SCOPES: readonly string[] = [\n 'openid',\n 'profile',\n 'credits',\n 'mcp:read',\n 'mcp:write',\n 'mcp:tools',\n]\n\n/**\n * Get OAuth URLs for a given environment with optional overrides.\n *\n * @param environment - The Nevermined environment name\n * @param overrides - Optional partial overrides for specific URLs\n * @returns Complete OAuth URLs configuration\n */\nexport function getOAuthUrls(\n environment: EnvironmentName,\n overrides?: Partial<OAuthUrls>,\n): OAuthUrls {\n // An overridden `authorizationUri` is passed through verbatim — the SDK cannot know whether it is\n // the Nevermined webapp or a foreign AS, so an operator who points it at the webapp includes\n // `?network=` themselves (documented on `OAuthUrls.authorizationUri`).\n //\n // Only a NON-EMPTY string overrides. `{ issuer: process.env.OAUTH_ISSUER }` with the variable unset\n // type-checks (exactOptionalPropertyTypes is off) and used to spread `undefined` over the computed\n // value, so `res.json` served the AS and OIDC documents WITHOUT their required `issuer` — for an\n // hour, under `Cache-Control: public` (payments#464 review). Same for `''`.\n const clean = Object.fromEntries(\n Object.entries(overrides ?? {}).filter(([, v]) => typeof v === 'string' && v.length > 0),\n ) as Partial<OAuthUrls>\n const baseUrls = getOAuthUrlsForEnvironment(\n environment,\n clean.tokenUri,\n clean.issuer !== undefined,\n )\n if (environment !== 'custom' && clean.issuer !== undefined && clean.issuer !== baseUrls.issuer) {\n // A NAMED environment's issuer is not configurable in fact: the web app returns the canonical\n // origin as RFC 9207 `iss` from its own fixed per-tier config, and these documents advertise\n // `authorization_response_iss_parameter_supported`, so a client compares `iss` with THIS value\n // and rejects every code. The override is still published — the operator's word is honoured —\n // but the failure must not arrive as an unexplained client-side rejection (#466 review). Keyed\n // on the value, like the other issuer warnings, so a corrected typo re-alerts.\n warnIssuerOnce(\n `override:${clean.issuer}`,\n `[Nevermined] oauthUrls.issuer '${clean.issuer}' differs from the canonical issuer of the ` +\n `'${environment}' environment, '${baseUrls.issuer}' — the iss the Nevermined consent page ` +\n `returns on every authorization response. An RFC 9207 client compares the two and will ` +\n `reject every authorization code. Remove oauthUrls.issuer, or set it to '${baseUrls.issuer}'.`,\n )\n }\n return { ...baseUrls, ...clean }\n}\n\n/**\n * RFC 9207 §3: an authorization server that returns the `iss` parameter on every authorization\n * response advertises `authorization_response_iss_parameter_supported: true`; §2.4 then has a client\n * REJECT any response lacking `iss`. An omitted flag DEFAULTS to `false` (§3), so the SDK publishes it\n * only where it is true and omits it everywhere else — never an explicit `false`, which would say the\n * same thing louder. True where: the consent page is the Nevermined web app, which has returned `iss`\n * (= the canonical API origin these documents publish as `issuer`) on every response since\n * nvm-monorepo#3532 — the API's own document advertises the same flag. That is every NAMED\n * environment (the decision, payments#466). Omitted for `custom` — its frontend may be an older or\n * self-hosted web app, and this SDK cannot tell (a `custom` server on a Nevermined backend AND\n * frontend is deliberately still omitted: the decision drew the line at the environment name, not at\n * a host guess) — and whenever `oauthUrls.authorizationUri` is overridden, since the consent page is\n * then an AS this SDK cannot vouch for, even when the value happens to point at the Nevermined web\n * app. The override predicate is the same \"non-empty string\" rule `getOAuthUrls` applies.\n *\n * Two limits of the omission, so nobody widens or narrows it for the wrong reason (#466 review):\n * - It is a TRADE, not a neutral default. §2.4's other half has a client SHOULD-discard a response\n * that carries `iss` from a server that did not advertise — exactly the state an override that\n * still points at the Nevermined web app (which returns `iss` unconditionally) lands in. Omitting\n * swaps the MUST-reject for the SHOULD-discard; the operator docs say so.\n * - It reaches only a client that discovers DIRECTLY against this server. One that follows the\n * protected-resource document's `authorization_servers` reads the Nevermined API's own metadata,\n * which advertises the flag unconditionally (`apps/api/src/well-known/well-known.service.ts`) —\n * so a `custom` deployment on a Nevermined backend with an older frontend is not shielded on\n * that route, whatever this document says.\n */\nfunction issParameterSupport(\n environment: EnvironmentName,\n overrides: Partial<OAuthUrls> | undefined,\n): { authorization_response_iss_parameter_supported: true } | Record<string, never> {\n const consentOverridden =\n typeof overrides?.authorizationUri === 'string' && overrides.authorizationUri.length > 0\n // An unknown environment name is served the sandbox documents by `getOAuthUrls`, and is not\n // `custom` — so the only name that omits is `custom` itself.\n return environment !== 'custom' && !consentOverridden\n ? { authorization_response_iss_parameter_supported: true }\n : {}\n}\n\n/**\n * Build Protected Resource Metadata (RFC 9728).\n * This metadata tells OAuth clients about the protected resource.\n *\n * @param config - OAuth configuration\n * @returns Protected Resource Metadata response object\n *\n * @example\n * ```typescript\n * const metadata = buildProtectedResourceMetadata({\n * baseUrl: 'http://localhost:5001',\n * agentId: 'agent_123',\n * environment: 'staging_sandbox'\n * })\n * // Returns: { resource: 'http://localhost:5001', authorization_servers: [...], ... }\n * ```\n */\nexport function buildProtectedResourceMetadata(config: OAuthConfig): ProtectedResourceMetadata {\n const scopes = config.scopes || [...DEFAULT_SCOPES]\n\n return {\n resource: config.baseUrl,\n authorization_servers: [resolveAuthorizationServer(config)],\n scopes_supported: scopes,\n bearer_methods_supported: ['header'],\n resource_documentation: `${config.baseUrl}/`,\n }\n}\n\n/**\n * Resolve the authorization-server identifier for `authorization_servers`.\n *\n * RFC 9728 §2 defines each entry as an AS **issuer identifier**, so it is, by construction, the\n * `issuer` this server's own AS document publishes — one derivation (`issuerFor` via `getOAuthUrls`),\n * so the two can never disagree: not on a `tokenUri` override, not on an `issuer` override (a\n * foreign AS named there is then also where clients are sent), not on malformed input. It used to be\n * derived separately from `tokenUri` with its own fallback, which put `issuer` and\n * `authorization_servers` on different values for a malformed override (payments#464 review).\n * It is NOT `config.baseUrl` — that is this MCP server, the protected *resource*.\n */\nfunction resolveAuthorizationServer(config: OAuthConfig): string {\n return getOAuthUrls(config.environment, config.oauthUrls).issuer\n}\n\n/**\n * Build MCP-specific Protected Resource Metadata.\n * Extends the base metadata with MCP capabilities information.\n *\n * @param config - OAuth configuration\n * @returns MCP Protected Resource Metadata response object\n *\n * @example\n * ```typescript\n * const metadata = buildMcpProtectedResourceMetadata({\n * baseUrl: 'http://localhost:5001',\n * agentId: 'agent_123',\n * environment: 'staging_sandbox',\n * tools: ['hello_world', 'weather']\n * })\n * ```\n */\nexport function buildMcpProtectedResourceMetadata(\n config: OAuthConfig,\n): McpProtectedResourceMetadata {\n const scopes = config.scopes || [...DEFAULT_SCOPES]\n\n return {\n resource: `${config.baseUrl}/mcp`,\n // See resolveAuthorizationServer: the AS is the issuer this server's own AS document\n // publishes (the backend API origin), never this MCP server (baseUrl).\n authorization_servers: [resolveAuthorizationServer(config)],\n scopes_supported: scopes,\n scopes_required: scopes,\n bearer_methods_supported: ['header'],\n resource_documentation: `${config.baseUrl}/`,\n mcp_capabilities: {\n tools: config.tools || [],\n protocol_version: config.protocolVersion || '2024-11-05',\n },\n }\n}\n\n/**\n * Build OAuth Authorization Server Metadata (RFC 8414).\n * This metadata describes the OAuth authorization server configuration.\n *\n * @param config - OAuth configuration\n * @returns Authorization Server Metadata response object\n *\n * @example\n * ```typescript\n * const metadata = buildAuthorizationServerMetadata({\n * baseUrl: 'http://localhost:5001',\n * agentId: 'agent_123',\n * environment: 'staging_sandbox'\n * })\n * ```\n */\nexport function buildAuthorizationServerMetadata(config: OAuthConfig): AuthorizationServerMetadata {\n const oauthUrls = getOAuthUrls(config.environment, config.oauthUrls)\n const scopes = config.scopes || [...DEFAULT_SCOPES]\n\n return {\n issuer: oauthUrls.issuer,\n authorization_endpoint: oauthUrls.authorizationUri,\n token_endpoint: oauthUrls.tokenUri,\n registration_endpoint: `${config.baseUrl}/register`,\n jwks_uri: oauthUrls.jwksUri,\n response_types_supported: ['code'],\n grant_types_supported: ['authorization_code', 'refresh_token'],\n code_challenge_methods_supported: ['S256'],\n scopes_supported: scopes,\n token_endpoint_auth_methods_supported: ['client_secret_post'],\n subject_types_supported: ['public'],\n ...issParameterSupport(config.environment, config.oauthUrls),\n }\n}\n\n/**\n * Build OpenID Connect Discovery Metadata.\n * Provides OIDC-compatible configuration for clients that expect OpenID Connect.\n *\n * @param config - OAuth configuration\n * @returns OIDC Configuration response object\n *\n * @example\n * ```typescript\n * const metadata = buildOidcConfiguration({\n * baseUrl: 'http://localhost:5001',\n * agentId: 'agent_123',\n * environment: 'staging_sandbox'\n * })\n * ```\n */\nexport function buildOidcConfiguration(config: OAuthConfig): OidcConfiguration {\n const oauthUrls = getOAuthUrls(config.environment, config.oauthUrls)\n const scopes = config.scopes || [...DEFAULT_SCOPES]\n const allScopes = scopes.includes('openid') ? scopes : ['openid', ...scopes]\n\n return {\n issuer: oauthUrls.issuer,\n authorization_endpoint: oauthUrls.authorizationUri,\n token_endpoint: oauthUrls.tokenUri,\n jwks_uri: oauthUrls.jwksUri,\n userinfo_endpoint: oauthUrls.userinfoUri,\n registration_endpoint: `${config.baseUrl}/register`,\n response_types_supported: ['code'],\n grant_types_supported: ['authorization_code', 'refresh_token'],\n code_challenge_methods_supported: ['S256'],\n token_endpoint_auth_methods_supported: ['none', 'client_secret_post'],\n subject_types_supported: ['public'],\n id_token_signing_alg_values_supported: ['RS256', 'HS256'],\n scopes_supported: allScopes,\n claims_supported: ['sub', 'iss', 'aud', 'exp', 'iat', 'name', 'email'],\n ...issParameterSupport(config.environment, config.oauthUrls),\n }\n}\n\n/**\n * Build server info response for the root endpoint.\n *\n * @param config - OAuth configuration\n * @param options - Additional options for the server info\n * @returns Server info response object\n */\nexport function buildServerInfoResponse(\n config: OAuthConfig,\n options?: {\n version?: string\n description?: string\n },\n): {\n name: string\n version: string\n description: string\n endpoints: Record<string, string>\n oauth: Record<string, any>\n tools: string[]\n resources: string[]\n prompts: string[]\n} {\n const oauthUrls = getOAuthUrls(config.environment, config.oauthUrls)\n const scopes = config.scopes || [...DEFAULT_SCOPES]\n\n return {\n name: config.serverName || 'MCP Server',\n version: options?.version || '1.0.0',\n description:\n options?.description || 'MCP server with Nevermined OAuth integration via Streamable HTTP',\n endpoints: {\n mcp: `${config.baseUrl}/mcp`,\n health: `${config.baseUrl}/health`,\n register: `${config.baseUrl}/register`,\n },\n oauth: {\n authorization_server_metadata: `${config.baseUrl}/.well-known/oauth-authorization-server`,\n protected_resource_metadata: `${config.baseUrl}/.well-known/oauth-protected-resource`,\n openid_configuration: `${config.baseUrl}/.well-known/openid-configuration`,\n authorization_endpoint: oauthUrls.authorizationUri,\n token_endpoint: oauthUrls.tokenUri,\n jwks_uri: oauthUrls.jwksUri,\n registration_endpoint: `${config.baseUrl}/register`,\n // agentId is optional under the plan-centric model; omit client_id when absent.\n ...(config.agentId ? { client_id: config.agentId } : {}),\n scopes: scopes,\n },\n tools: config.tools || [],\n resources: config.resources || [],\n prompts: config.prompts || [],\n }\n}\n"]}
|
package/dist/mcp/index.d.ts
CHANGED
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
*
|
|
18
18
|
* // Configure MCP integration
|
|
19
19
|
* payments.mcp.configure({
|
|
20
|
-
* planId: process.env.NVM_PLAN_ID!, //
|
|
20
|
+
* planId: process.env.NVM_PLAN_ID!, // optional — omit it if every tool sets its own
|
|
21
21
|
* agentId: process.env.NVM_AGENT_ID, // optional
|
|
22
22
|
* serverName: 'my-mcp-server'
|
|
23
23
|
* })
|
|
@@ -34,7 +34,7 @@
|
|
|
34
34
|
* // Start a managed server with all OAuth endpoints
|
|
35
35
|
* const { baseUrl, stop } = await payments.mcp.startServer({
|
|
36
36
|
* port: 5001,
|
|
37
|
-
* planId: process.env.NVM_PLAN_ID!, //
|
|
37
|
+
* planId: process.env.NVM_PLAN_ID!, // optional — falls back to configure()
|
|
38
38
|
* agentId: process.env.NVM_AGENT_ID, // optional
|
|
39
39
|
* serverName: 'my-mcp-server',
|
|
40
40
|
* tools: ['hello_world']
|
|
@@ -50,7 +50,7 @@
|
|
|
50
50
|
* // Create OAuth router
|
|
51
51
|
* const router = payments.mcp.createRouter({
|
|
52
52
|
* baseUrl: 'http://localhost:5001',
|
|
53
|
-
* planId: 'plan_123', //
|
|
53
|
+
* planId: 'plan_123', // optional — falls back to configure()
|
|
54
54
|
* agentId: 'agent_123', // optional
|
|
55
55
|
* serverName: 'my-mcp-server'
|
|
56
56
|
* })
|
|
@@ -68,7 +68,7 @@ export type { CreditsContext, CreditsOption, PaywallOptions, McpConfig, PaywallC
|
|
|
68
68
|
export type { OAuthUrls, OAuthConfig, HttpRouterConfig, HttpServerConfig, HttpServerResult, ProtectedResourceMetadata, McpProtectedResourceMetadata, AuthorizationServerMetadata, OidcConfiguration, ClientRegistrationRequest, ClientRegistrationResponse, ServerInfoResponse, } from './types/http.types.js';
|
|
69
69
|
export { buildExtraFromHttpHeaders, buildExtraFromHttpRequest } from './utils/extra.js';
|
|
70
70
|
export type { McpToolConfig, McpResourceConfig, McpPromptConfig, McpRegistrationOptions, ToolHandler, ResourceHandler, PromptHandler, McpServerConfig, McpServerResult, ServerInfo, ToolContext, ResourceContext, PromptContext, } from './types/server.types.js';
|
|
71
|
-
export { getOAuthUrls, buildProtectedResourceMetadata, buildMcpProtectedResourceMetadata, buildAuthorizationServerMetadata, buildOidcConfiguration, buildServerInfoResponse, createOAuthRouter, createCorsMiddleware, createJsonMiddleware, createRequireAuthMiddleware, createHttpLoggingMiddleware, startManagedServer, createMcpApp, ClientRegistrationError, } from './http/index.js';
|
|
71
|
+
export { getOAuthUrls, resolveOAuthTier, OAUTH_TIER_PARAM, OAUTH_TIERS, type OAuthTier, buildProtectedResourceMetadata, buildMcpProtectedResourceMetadata, buildAuthorizationServerMetadata, buildOidcConfiguration, buildServerInfoResponse, createOAuthRouter, createCorsMiddleware, createJsonMiddleware, createRequireAuthMiddleware, createHttpLoggingMiddleware, startManagedServer, createMcpApp, ClientRegistrationError, } from './http/index.js';
|
|
72
72
|
/**
|
|
73
73
|
* Extended MCP configuration including HTTP server options.
|
|
74
74
|
*/
|
package/dist/mcp/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/mcp/index.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/mcp/index.ts"],"names":[],"mappings":"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"}
|