@adcp/sdk 14.4.0 → 15.0.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.
Files changed (60) hide show
  1. package/bin/adcp.js +6 -1
  2. package/dist/lib/auth/oauth/ClientCredentialsFlow.js +4 -1
  3. package/dist/lib/auth/oauth/ClientCredentialsFlow.mjs +4 -1
  4. package/dist/lib/auth/oauth/MCPOAuthProvider.d.mts +19 -6
  5. package/dist/lib/auth/oauth/MCPOAuthProvider.d.ts +19 -6
  6. package/dist/lib/auth/oauth/MCPOAuthProvider.js +95 -30
  7. package/dist/lib/auth/oauth/MCPOAuthProvider.mjs +96 -30
  8. package/dist/lib/auth/oauth/NonInteractiveFlowHandler.d.mts +1 -1
  9. package/dist/lib/auth/oauth/NonInteractiveFlowHandler.d.ts +1 -1
  10. package/dist/lib/auth/oauth/NonInteractiveFlowHandler.js +1 -1
  11. package/dist/lib/auth/oauth/NonInteractiveFlowHandler.mjs +1 -1
  12. package/dist/lib/auth/oauth/client-credentials-schema.d.mts +17 -0
  13. package/dist/lib/auth/oauth/client-credentials-schema.d.ts +17 -0
  14. package/dist/lib/auth/oauth/client-credentials-schema.js +37 -0
  15. package/dist/lib/auth/oauth/client-credentials-schema.mjs +13 -0
  16. package/dist/lib/auth/oauth/file-storage.d.mts +3 -3
  17. package/dist/lib/auth/oauth/file-storage.d.ts +3 -3
  18. package/dist/lib/auth/oauth/file-storage.js +12 -5
  19. package/dist/lib/auth/oauth/file-storage.mjs +12 -5
  20. package/dist/lib/auth/oauth/index.d.mts +10 -6
  21. package/dist/lib/auth/oauth/index.d.ts +10 -6
  22. package/dist/lib/auth/oauth/index.js +9 -3
  23. package/dist/lib/auth/oauth/index.mjs +8 -3
  24. package/dist/lib/auth/oauth/types.d.mts +9 -2
  25. package/dist/lib/auth/oauth/types.d.ts +9 -2
  26. package/dist/lib/auth/oauth/types.js +3 -2
  27. package/dist/lib/auth/oauth/types.mjs +3 -2
  28. package/dist/lib/auth/oauth/web-flow.d.mts +2 -0
  29. package/dist/lib/auth/oauth/web-flow.d.ts +2 -0
  30. package/dist/lib/auth/oauth/web-flow.js +42 -9
  31. package/dist/lib/auth/oauth/web-flow.mjs +42 -9
  32. package/dist/lib/index.d.mts +1 -1
  33. package/dist/lib/index.d.ts +1 -1
  34. package/dist/lib/index.js +2 -0
  35. package/dist/lib/index.mjs +3 -1
  36. package/dist/lib/schemas/index.d.mts +2 -0
  37. package/dist/lib/schemas/index.d.ts +2 -0
  38. package/dist/lib/schemas/index.js +3 -0
  39. package/dist/lib/schemas/index.mjs +2 -0
  40. package/dist/lib/schemas-data/v2.5/_provenance.json +1 -1
  41. package/dist/lib/testing/client.js +8 -3
  42. package/dist/lib/testing/client.mjs +8 -3
  43. package/dist/lib/testing/storyboard/validations.d.mts +1 -1
  44. package/dist/lib/testing/storyboard/validations.d.ts +1 -1
  45. package/dist/lib/testing/types.d.mts +10 -1
  46. package/dist/lib/testing/types.d.ts +10 -1
  47. package/dist/lib/version.d.mts +3 -3
  48. package/dist/lib/version.d.ts +3 -3
  49. package/dist/lib/version.js +3 -3
  50. package/dist/lib/version.mjs +3 -3
  51. package/docs/TYPE-SUMMARY.md +1 -1
  52. package/docs/ZOD-SCHEMAS.md +19 -0
  53. package/docs/guides/OAUTH-ISSUER-BINDING.md +46 -0
  54. package/docs/guides/WEB-OAUTH.md +58 -163
  55. package/docs/guides/account-resolution.md +1 -1
  56. package/docs/llms.txt +1 -1
  57. package/docs/migration-14.0-to-14.1.md +1 -1
  58. package/docs/migration-14.x-rc-worksheet.md +7 -7
  59. package/docs/migration-oauth-issuer-bindings.md +14 -79
  60. package/package.json +1 -1
@@ -124,6 +124,8 @@ async function startWebOAuthFlow(opts) {
124
124
  throw new OAuthError(`No OAuth metadata at ${asUrl.toString()}`, "no_authorization_server_metadata", agent.id);
125
125
  }
126
126
  assertOAuthServerIssuer(asMetadata, asUrl.toString());
127
+ const authorizationServerIssuer = asUrl.toString();
128
+ assertSavedCredentialIssuers(agent, authorizationServerIssuer);
127
129
  const resource = resourceOverride ? new URL(resourceOverride) : prm?.resource ? new URL(prm.resource) : resourceUrlFromServerUrl(new URL(agent.agent_uri));
128
130
  const baseClientMetadata = {
129
131
  ...DEFAULT_CLIENT_METADATA,
@@ -138,7 +140,8 @@ async function startWebOAuthFlow(opts) {
138
140
  asMetadata,
139
141
  clientMetadata: baseClientMetadata,
140
142
  fetchFn: guardedFetch,
141
- allowConfidentialClient
143
+ allowConfidentialClient,
144
+ issuer: authorizationServerIssuer
142
145
  });
143
146
  const state = (generateState ?? defaultGenerateState)();
144
147
  const { authorizationUrl, codeVerifier } = await startAuthorization(asUrl.toString(), {
@@ -166,6 +169,7 @@ async function startWebOAuthFlow(opts) {
166
169
  resourceOverrideSnapshot: agent.oauth_resource ?? null,
167
170
  scope,
168
171
  authorizationServerUrl: asUrl.toString(),
172
+ authorizationServerIssuer,
169
173
  clientInformation,
170
174
  createdAt: now,
171
175
  expiresAt,
@@ -211,11 +215,16 @@ async function completeWebOAuthFlow(opts) {
211
215
  fetchFn: guardedFetch
212
216
  });
213
217
  assertOAuthServerIssuer(asMetadata, flow.authorizationServerUrl);
218
+ assertFrozenIssuer(flow);
214
219
  assertOAuthCredentialIssuer(
215
220
  flow.clientInformation,
216
- flow.authorizationServerUrl,
221
+ flow.authorizationServerIssuer,
217
222
  !!flow.clientInformation.client_secret
218
223
  );
224
+ if (agentStorage) {
225
+ agentForPersistence = await agentStorage.loadAgent(flow.agentId);
226
+ assertAgentUnchangedForFlow(agentForPersistence, flow);
227
+ }
219
228
  let tokens;
220
229
  try {
221
230
  tokens = await exchangeAuthorization(flow.authorizationServerUrl, {
@@ -227,7 +236,7 @@ async function completeWebOAuthFlow(opts) {
227
236
  resource: flow.resource ? new URL(flow.resource) : void 0,
228
237
  fetchFn: guardedFetch
229
238
  });
230
- tokens = { ...tokens, issuer: flow.authorizationServerUrl };
239
+ tokens = { ...tokens, issuer: flow.authorizationServerIssuer };
231
240
  } catch (err) {
232
241
  throw wrapTokenExchangeError(err);
233
242
  }
@@ -241,7 +250,8 @@ async function completeWebOAuthFlow(opts) {
241
250
  } else if (flow.resourceOverrideAction === "clear") {
242
251
  delete agentForPersistence.oauth_resource;
243
252
  }
244
- delete agentForPersistence.oauth_code_verifier;
253
+ agentForPersistence.oauth_code_verifier = void 0;
254
+ agentForPersistence.oauth_discovery_state = void 0;
245
255
  await agentStorage.saveAgent(agentForPersistence);
246
256
  persisted = true;
247
257
  }
@@ -253,6 +263,20 @@ async function completeWebOAuthFlow(opts) {
253
263
  persisted
254
264
  };
255
265
  }
266
+ function assertSavedCredentialIssuers(agent, issuer) {
267
+ if (agent.oauth_tokens) assertOAuthCredentialIssuer(agent.oauth_tokens, issuer, !!agent.oauth_tokens.refresh_token);
268
+ if (agent.oauth_client) assertOAuthCredentialIssuer(agent.oauth_client, issuer, !!agent.oauth_client.client_secret);
269
+ }
270
+ function assertFrozenIssuer(flow) {
271
+ if (!flow.authorizationServerIssuer) {
272
+ throw new OAuthError(
273
+ "Pending OAuth flow lacks a validated authorization-server issuer. Start a new owner sign-in.",
274
+ "oauth_issuer_required",
275
+ flow.agentId
276
+ );
277
+ }
278
+ assertOAuthServerIssuer({ issuer: flow.authorizationServerIssuer }, flow.authorizationServerUrl);
279
+ }
256
280
  function assertAgentUnchangedForFlow(agent, flow) {
257
281
  if (!agent) {
258
282
  throw new AgentVanishedDuringFlowError(flow.agentId);
@@ -260,6 +284,13 @@ function assertAgentUnchangedForFlow(agent, flow) {
260
284
  if (agent.agent_uri !== flow.agentUrl) {
261
285
  throw new AgentChangedDuringFlowError(flow.agentId);
262
286
  }
287
+ if (!agent.oauth_client) throw new AgentChangedDuringFlowError(flow.agentId);
288
+ const currentClient = toMCPClientInfo(agent.oauth_client);
289
+ for (const key of ["client_id", "client_secret", "client_secret_expires_at", "issuer"]) {
290
+ if (currentClient[key] !== flow.clientInformation[key]) throw new AgentChangedDuringFlowError(flow.agentId);
291
+ }
292
+ assertFrozenIssuer(flow);
293
+ assertSavedCredentialIssuers(agent, flow.authorizationServerIssuer);
263
294
  if (Object.prototype.hasOwnProperty.call(flow, "resourceOverrideSnapshot") && (agent.oauth_resource ?? null) !== flow.resourceOverrideSnapshot) {
264
295
  throw new AgentChangedDuringFlowError(flow.agentId);
265
296
  }
@@ -395,9 +426,8 @@ function createSsrfSafeOAuthFetch(trustedFetchFn, allowHttp) {
395
426
  });
396
427
  }
397
428
  async function resolveClientInformation(args) {
398
- const { agent, agentStorage, asUrl, asMetadata, clientMetadata, fetchFn, allowConfidentialClient } = args;
429
+ const { agent, agentStorage, asUrl, asMetadata, clientMetadata, fetchFn, allowConfidentialClient, issuer } = args;
399
430
  if (agent.oauth_client) {
400
- assertOAuthCredentialIssuer(agent.oauth_client, asUrl.toString(), !!agent.oauth_client.client_secret);
401
431
  return toMCPClientInfo(agent.oauth_client);
402
432
  }
403
433
  if (!asMetadata.registration_endpoint) {
@@ -407,17 +437,20 @@ async function resolveClientInformation(args) {
407
437
  agent.id
408
438
  );
409
439
  }
410
- const registration = await registerClient(asUrl.toString(), {
440
+ const response = await registerClient(asUrl.toString(), {
411
441
  metadata: asMetadata,
412
442
  clientMetadata,
413
443
  fetchFn
414
444
  });
415
- const registered = { ...registration, issuer: asUrl.toString() };
445
+ const registered = { ...response, issuer };
416
446
  if (registered.client_secret && !allowConfidentialClient) {
417
447
  throw new ConfidentialClientNotAllowedError(agent.id);
418
448
  }
419
449
  if (agentStorage) {
420
- const fresh = await agentStorage.loadAgent(agent.id) ?? agent;
450
+ const fresh = await agentStorage.loadAgent(agent.id);
451
+ if (!fresh) throw new AgentVanishedDuringFlowError(agent.id);
452
+ if (fresh.agent_uri !== agent.agent_uri || fresh.oauth_client) throw new AgentChangedDuringFlowError(agent.id);
453
+ assertSavedCredentialIssuers(fresh, issuer);
421
454
  fresh.oauth_client = fromMCPClientInfo(registered);
422
455
  await agentStorage.saveAgent(fresh);
423
456
  }
@@ -186,7 +186,7 @@ export { getAuthToken, createAdCPHeaders, createMCPAuthHeaders, createAuthentica
186
186
  export { parseWWWAuthenticate, decodeAccessTokenClaims, validateTokenAudience, type WWWAuthenticateChallenge, type DecodedJWTHeader, type DecodedJWTClaims, type DecodedAccessToken, type TokenAudienceResult, InvalidTokenError, InsufficientScopeError, } from './auth/oauth/index.mjs';
187
187
  export { runAuthDiagnosis, AUTH_DIAGNOSIS_SCHEMA_VERSION, type DiagnoseOptions, type HttpCapture as DiagnosisHttpCapture, type DiagnosisStep, type Hypothesis as DiagnosisHypothesis, type HypothesisVerdict as DiagnosisHypothesisVerdict, type AuthDiagnosisReport, } from './auth/oauth/index.mjs';
188
188
  export { NeedsAuthorizationError, discoverAuthorizationRequirements, hasValidatedMcpAuthorizationRequirements, createFileOAuthStorage, bindAgentStorage, getAgentStorage, unbindAgentStorage, type AuthorizationRequirements, type DiscoverAuthorizationOptions, type FileOAuthStorageOptions, } from './auth/oauth/index.mjs';
189
- export { exchangeClientCredentials, ensureClientCredentialsTokens, ClientCredentialsExchangeError, MissingEnvSecretError, resolveSecret, isEnvSecretReference, toEnvSecretReference, extractEnvSecretName, type ExchangeClientCredentialsOptions, type EnsureClientCredentialsOptions, type AgentOAuthClientCredentials, } from './auth/oauth/index.mjs';
189
+ export { exchangeClientCredentials, ensureClientCredentialsTokens, ClientCredentialsExchangeError, MissingEnvSecretError, resolveSecret, isEnvSecretReference, toEnvSecretReference, extractEnvSecretName, type ExchangeClientCredentialsOptions, type EnsureClientCredentialsOptions, type AgentOAuthClientCredentials, AgentOAuthClientCredentialsSchema, } from './auth/oauth/index.mjs';
190
190
  export { validateAgentUrl, validateAdCPResponse, getExpectedSchema, handleAdCPResponse } from './validation/index.mjs';
191
191
  export { ProtocolClient, callMCPTool, callA2ATool, createA2AClientFromCardUrl, createMCPClient, createA2AClient, closeMCPConnections, closeOAuthConnections, bundleSupportsAdcpVersionField, BODY_SNIPPET_TIMEOUT_MS, OBSERVER_FLUSH_TIMEOUT_MS, sanitizeTransportHeaders, sanitizeTransportUrl, } from './protocols/index.mjs';
192
192
  export { toReleasePrecisionWire, validateAdcpVersionWire } from './validation/schema-loader.mjs';
@@ -186,7 +186,7 @@ export { getAuthToken, createAdCPHeaders, createMCPAuthHeaders, createAuthentica
186
186
  export { parseWWWAuthenticate, decodeAccessTokenClaims, validateTokenAudience, type WWWAuthenticateChallenge, type DecodedJWTHeader, type DecodedJWTClaims, type DecodedAccessToken, type TokenAudienceResult, InvalidTokenError, InsufficientScopeError, } from './auth/oauth';
187
187
  export { runAuthDiagnosis, AUTH_DIAGNOSIS_SCHEMA_VERSION, type DiagnoseOptions, type HttpCapture as DiagnosisHttpCapture, type DiagnosisStep, type Hypothesis as DiagnosisHypothesis, type HypothesisVerdict as DiagnosisHypothesisVerdict, type AuthDiagnosisReport, } from './auth/oauth';
188
188
  export { NeedsAuthorizationError, discoverAuthorizationRequirements, hasValidatedMcpAuthorizationRequirements, createFileOAuthStorage, bindAgentStorage, getAgentStorage, unbindAgentStorage, type AuthorizationRequirements, type DiscoverAuthorizationOptions, type FileOAuthStorageOptions, } from './auth/oauth';
189
- export { exchangeClientCredentials, ensureClientCredentialsTokens, ClientCredentialsExchangeError, MissingEnvSecretError, resolveSecret, isEnvSecretReference, toEnvSecretReference, extractEnvSecretName, type ExchangeClientCredentialsOptions, type EnsureClientCredentialsOptions, type AgentOAuthClientCredentials, } from './auth/oauth';
189
+ export { exchangeClientCredentials, ensureClientCredentialsTokens, ClientCredentialsExchangeError, MissingEnvSecretError, resolveSecret, isEnvSecretReference, toEnvSecretReference, extractEnvSecretName, type ExchangeClientCredentialsOptions, type EnsureClientCredentialsOptions, type AgentOAuthClientCredentials, AgentOAuthClientCredentialsSchema, } from './auth/oauth';
190
190
  export { validateAgentUrl, validateAdCPResponse, getExpectedSchema, handleAdCPResponse } from './validation';
191
191
  export { ProtocolClient, callMCPTool, callA2ATool, createA2AClientFromCardUrl, createMCPClient, createA2AClient, closeMCPConnections, closeOAuthConnections, bundleSupportsAdcpVersionField, BODY_SNIPPET_TIMEOUT_MS, OBSERVER_FLUSH_TIMEOUT_MS, sanitizeTransportHeaders, sanitizeTransportUrl, } from './protocols';
192
192
  export { toReleasePrecisionWire, validateAdcpVersionWire } from './validation/schema-loader';
package/dist/lib/index.js CHANGED
@@ -48,6 +48,7 @@ __export(index_exports, {
48
48
  AdagentsJsonSchema: () => import_wellknown_schemas.AdagentsJsonSchema,
49
49
  AgentClient: () => import_AgentClient.AgentClient,
50
50
  AgentNotFoundError: () => import_errors.AgentNotFoundError,
51
+ AgentOAuthClientCredentialsSchema: () => import_oauth4.AgentOAuthClientCredentialsSchema,
51
52
  Asset: () => import_asset_builders.Asset,
52
53
  AsyncHandler: () => import_AsyncHandler.AsyncHandler,
53
54
  AuthenticationCredentialsRejectedError: () => import_errors.AuthenticationCredentialsRejectedError,
@@ -888,6 +889,7 @@ function createAdCPClientFromEnv() {
888
889
  AdagentsJsonSchema,
889
890
  AgentClient,
890
891
  AgentNotFoundError,
892
+ AgentOAuthClientCredentialsSchema,
891
893
  Asset,
892
894
  AsyncHandler,
893
895
  AuthenticationCredentialsRejectedError,
@@ -445,7 +445,8 @@ import {
445
445
  resolveSecret,
446
446
  isEnvSecretReference,
447
447
  toEnvSecretReference,
448
- extractEnvSecretName
448
+ extractEnvSecretName,
449
+ AgentOAuthClientCredentialsSchema
449
450
  } from "./auth/oauth/index.mjs";
450
451
  import { validateAgentUrl, validateAdCPResponse, getExpectedSchema, handleAdCPResponse } from "./validation/index.mjs";
451
452
  import {
@@ -847,6 +848,7 @@ export {
847
848
  AdagentsJsonSchema,
848
849
  AgentClient,
849
850
  AgentNotFoundError,
851
+ AgentOAuthClientCredentialsSchema,
850
852
  Asset,
851
853
  AsyncHandler,
852
854
  AuthenticationCredentialsRejectedError,
@@ -46,6 +46,8 @@ import type { KnownToolRequestSchemas } from '../utils/tool-request-schemas.mjs'
46
46
  import { getSchemaDocumentByRef, type Direction, type ResolvedToolSchemaDocument, type ResponseVariant } from '../validation/schema-loader.mjs';
47
47
  import type { ValidateFunction } from 'ajv';
48
48
  export * from '../types/schemas.generated.mjs';
49
+ export { AgentOAuthClientCredentialsSchema } from '../auth/oauth/client-credentials-schema.mjs';
50
+ export type { AgentOAuthClientCredentials } from '../types/adcp.mjs';
49
51
  export type { PlacementPresentationDocument, PlacementPresentationReference } from '../types/core.generated.mjs';
50
52
  type LooseObjectShapeFor<T extends object> = {
51
53
  [K in keyof T]-?: undefined extends T[K] ? z.ZodOptional<z.ZodType<Exclude<T[K], undefined>, Exclude<T[K], undefined>>> : z.ZodType<T[K], T[K]>;
@@ -46,6 +46,8 @@ import type { KnownToolRequestSchemas } from '../utils/tool-request-schemas';
46
46
  import { getSchemaDocumentByRef, type Direction, type ResolvedToolSchemaDocument, type ResponseVariant } from '../validation/schema-loader';
47
47
  import type { ValidateFunction } from 'ajv';
48
48
  export * from '../types/schemas.generated';
49
+ export { AgentOAuthClientCredentialsSchema } from '../auth/oauth/client-credentials-schema';
50
+ export type { AgentOAuthClientCredentials } from '../types/adcp';
49
51
  export type { PlacementPresentationDocument, PlacementPresentationReference } from '../types/core.generated';
50
52
  type LooseObjectShapeFor<T extends object> = {
51
53
  [K in keyof T]-?: undefined extends T[K] ? z.ZodOptional<z.ZodType<Exclude<T[K], undefined>, Exclude<T[K], undefined>>> : z.ZodType<T[K], T[K]>;
@@ -29,6 +29,7 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
29
29
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
30
30
  var schemas_exports = {};
31
31
  __export(schemas_exports, {
32
+ AgentOAuthClientCredentialsSchema: () => import_client_credentials_schema.AgentOAuthClientCredentialsSchema,
32
33
  BiddingPolicySchema: () => import_bidding_policy.BiddingPolicySchema,
33
34
  CanonicalBudgetAllocationSchema: () => import_budget_allocation.CanonicalBudgetAllocationSchema,
34
35
  GetProductsRequestSchema: () => GetProductsRequestSchema,
@@ -56,6 +57,7 @@ var import_tool_request_schemas = require('../utils/tool-request-schemas.js');
56
57
  var import_schema_loader = require('../validation/schema-loader.js');
57
58
  var import_adcp_version_config = require('../utils/adcp-version-config.js');
58
59
  __reExport(schemas_exports, require('../types/schemas.generated.js'), module.exports);
60
+ var import_client_credentials_schema = require('../auth/oauth/client-credentials-schema.js');
59
61
  var import_bidding_policy = require('../validation/bidding-policy.js');
60
62
  var import_budget_allocation = require('../validation/budget-allocation.js');
61
63
  var import_tool_request_schemas2 = require('../utils/tool-request-schemas.js');
@@ -114,6 +116,7 @@ function customToolForSchema(name, description, inputSchema, handler) {
114
116
  }
115
117
  // Annotate the CommonJS export names for ESM import in node:
116
118
  0 && (module.exports = {
119
+ AgentOAuthClientCredentialsSchema,
117
120
  BiddingPolicySchema,
118
121
  CanonicalBudgetAllocationSchema,
119
122
  GetProductsRequestSchema,
@@ -9,6 +9,7 @@ import {
9
9
  } from "../validation/schema-loader.mjs";
10
10
  import { resolveAdcpVersion } from "../utils/adcp-version-config.mjs";
11
11
  export * from "../types/schemas.generated.mjs";
12
+ import { AgentOAuthClientCredentialsSchema } from "../auth/oauth/client-credentials-schema.mjs";
12
13
  const LegacyGetProductsRequestSchema = schemas.GetProductsRequestSchema;
13
14
  const canonicalGetProductsFields = GetProductsRequest_FieldsValues.filter(
14
15
  (field) => field !== "format_ids"
@@ -71,6 +72,7 @@ function customToolForSchema(name, description, inputSchema, handler) {
71
72
  return { description, inputSchema, handler };
72
73
  }
73
74
  export {
75
+ AgentOAuthClientCredentialsSchema,
74
76
  BiddingPolicySchema,
75
77
  CanonicalBudgetAllocationSchema,
76
78
  GetProductsRequestSchema,
@@ -4,5 +4,5 @@
4
4
  "source_sha": "4e553ad955f83b49c7d221ab5c3ff78237ad02e3",
5
5
  "source_tarball_sha256": "580656d6466ef9f0d1119985e6726c2efea718dc671e2ad30957fcb2fd54af0f",
6
6
  "upstream_adcp_version": "2.5.3",
7
- "synced_at": "2026-10-06T19:28:36.184Z"
7
+ "synced_at": "2026-10-07T00:14:46.446Z"
8
8
  }
@@ -52,6 +52,7 @@ var import_node_crypto = require("node:crypto");
52
52
  var import_client_hooks = require('../validation/client-hooks.js');
53
53
  var import_error_extraction = require('../utils/error-extraction.js');
54
54
  var import_client = require('../signing/client.js');
55
+ var import_storage_registry = require('../auth/oauth/storage-registry.js');
55
56
  const TEST_CLIENT_VERSION_OPTIONS = /* @__PURE__ */ Symbol("adcp.testClientVersionOptions");
56
57
  const TEST_CLIENT_SCOPE_SALT = (0, import_node_crypto.randomBytes)(32);
57
58
  function resolveAuthPrincipal(options) {
@@ -123,6 +124,7 @@ function createTestClient(agentUrl, protocol = "mcp", options = {}) {
123
124
  } else if (options.auth.type === "oauth") {
124
125
  agentConfig.oauth_tokens = options.auth.tokens;
125
126
  if (options.auth.client) agentConfig.oauth_client = options.auth.client;
127
+ if (options.auth.storage) (0, import_storage_registry.bindAgentStorage)(agentConfig, options.auth.storage);
126
128
  } else if (options.auth.type === "oauth_client_credentials") {
127
129
  agentConfig.oauth_client_credentials = options.auth.credentials;
128
130
  if (options.auth.tokens) agentConfig.oauth_tokens = options.auth.tokens;
@@ -160,6 +162,7 @@ function createTestClient(agentUrl, protocol = "mcp", options = {}) {
160
162
  ...authMode !== void 0 && { authMode },
161
163
  ...requestScopeMode !== void 0 && { requestScopeMode },
162
164
  ...requestSigningMode !== void 0 && { requestSigningMode },
165
+ ...options.auth?.type === "oauth" && options.auth.storage && { oauthStorage: options.auth.storage },
163
166
  ...options.transport?.trustedFetchFn && { fetchFn: options.transport.trustedFetchFn },
164
167
  ...options.transport?.allowPrivateIp !== void 0 && { allowPrivateIp: options.transport.allowPrivateIp },
165
168
  ...options.transport?.maxResponseBytes !== void 0 && {
@@ -198,13 +201,14 @@ function testClientMatchesVersionOptions(client, agentUrl, options) {
198
201
  const expectedAuthMode = authReuseMode(effectiveOptions);
199
202
  const expectedRequestScopeMode = requestScopeReuseMode(effectiveOptions);
200
203
  const expectedRequestSigningMode = requestSigningReuseMode(effectiveOptions.functional_request_signing);
204
+ const expectedOAuthStorage = effectiveOptions.auth?.type === "oauth" ? effectiveOptions.auth.storage : void 0;
201
205
  if (!meta) {
202
- return expectedRequestSigningMode === void 0 && effectiveOptions.adcpVersion === void 0 && effectiveOptions.versionEnvelope === void 0 && effectiveOptions.transport === void 0;
206
+ return expectedOAuthStorage === void 0 && expectedRequestSigningMode === void 0 && effectiveOptions.adcpVersion === void 0 && effectiveOptions.versionEnvelope === void 0 && effectiveOptions.transport === void 0;
203
207
  }
204
208
  const expectedAdcpVersion = effectiveOptions.adcpVersion ?? import_version.ADCP_VERSION;
205
209
  const expectedWireAdcpVersion = effectiveOptions.wireAdcpVersion;
206
210
  const expectedVersionEnvelope = effectiveOptions.versionEnvelope ?? "auto";
207
- return meta.agentUrl === agentUrl && meta.protocol === (effectiveOptions.protocol ?? "mcp") && meta.adcpVersion === expectedAdcpVersion && meta.wireAdcpVersion === expectedWireAdcpVersion && meta.versionEnvelope === expectedVersionEnvelope && meta.strictResponseSchemaValidation === (effectiveOptions.strictResponseSchemaValidation !== false) && meta.authMode === expectedAuthMode && meta.requestScopeMode === expectedRequestScopeMode && meta.requestSigningMode === expectedRequestSigningMode && meta.fetchFn === effectiveOptions.transport?.trustedFetchFn && meta.allowPrivateIp === effectiveOptions.transport?.allowPrivateIp && meta.maxResponseBytes === effectiveOptions.transport?.maxResponseBytes && meta.requestTimeoutMs === effectiveOptions.transport?.requestTimeoutMs && meta.legacyCompatEnabled === effectiveOptions.transport?.legacyCompat?.enabled;
211
+ return meta.agentUrl === agentUrl && meta.protocol === (effectiveOptions.protocol ?? "mcp") && meta.adcpVersion === expectedAdcpVersion && meta.wireAdcpVersion === expectedWireAdcpVersion && meta.versionEnvelope === expectedVersionEnvelope && meta.strictResponseSchemaValidation === (effectiveOptions.strictResponseSchemaValidation !== false) && meta.authMode === expectedAuthMode && meta.requestScopeMode === expectedRequestScopeMode && meta.requestSigningMode === expectedRequestSigningMode && meta.oauthStorage === expectedOAuthStorage && meta.fetchFn === effectiveOptions.transport?.trustedFetchFn && meta.allowPrivateIp === effectiveOptions.transport?.allowPrivateIp && meta.maxResponseBytes === effectiveOptions.transport?.maxResponseBytes && meta.requestTimeoutMs === effectiveOptions.transport?.requestTimeoutMs && meta.legacyCompatEnabled === effectiveOptions.transport?.legacyCompat?.enabled;
208
212
  }
209
213
  function withTestKitAuthDefaults(options) {
210
214
  if (options.auth) return options;
@@ -240,9 +244,10 @@ function requestScopeReuseMode(options) {
240
244
  Object.entries(options.headers).map(([name, value]) => [name.toLowerCase(), value]).sort(([a], [b]) => a.localeCompare(b))
241
245
  ) : void 0;
242
246
  if (!options.auth && !headers && !options.test_session_id && !options.userAgent) return void 0;
247
+ const auth = options.auth?.type === "oauth" ? { ...options.auth, storage: void 0 } : options.auth;
243
248
  return testClientScopeDisambiguator(
244
249
  JSON.stringify({
245
- auth: options.auth,
250
+ auth,
246
251
  headers,
247
252
  testSessionId: options.test_session_id,
248
253
  userAgent: options.userAgent
@@ -12,6 +12,7 @@ import { createHmac, hkdfSync, randomBytes } from "node:crypto";
12
12
  import { validateIncomingResponse } from "../validation/client-hooks.mjs";
13
13
  import { extractVersionUnsupportedDetails } from "../utils/error-extraction.mjs";
14
14
  import { buildAgentSigningContext } from "../signing/client.mjs";
15
+ import { bindAgentStorage } from "../auth/oauth/storage-registry.mjs";
15
16
  const TEST_CLIENT_VERSION_OPTIONS = /* @__PURE__ */ Symbol("adcp.testClientVersionOptions");
16
17
  const TEST_CLIENT_SCOPE_SALT = randomBytes(32);
17
18
  function resolveAuthPrincipal(options) {
@@ -83,6 +84,7 @@ function createTestClient(agentUrl, protocol = "mcp", options = {}) {
83
84
  } else if (options.auth.type === "oauth") {
84
85
  agentConfig.oauth_tokens = options.auth.tokens;
85
86
  if (options.auth.client) agentConfig.oauth_client = options.auth.client;
87
+ if (options.auth.storage) bindAgentStorage(agentConfig, options.auth.storage);
86
88
  } else if (options.auth.type === "oauth_client_credentials") {
87
89
  agentConfig.oauth_client_credentials = options.auth.credentials;
88
90
  if (options.auth.tokens) agentConfig.oauth_tokens = options.auth.tokens;
@@ -120,6 +122,7 @@ function createTestClient(agentUrl, protocol = "mcp", options = {}) {
120
122
  ...authMode !== void 0 && { authMode },
121
123
  ...requestScopeMode !== void 0 && { requestScopeMode },
122
124
  ...requestSigningMode !== void 0 && { requestSigningMode },
125
+ ...options.auth?.type === "oauth" && options.auth.storage && { oauthStorage: options.auth.storage },
123
126
  ...options.transport?.trustedFetchFn && { fetchFn: options.transport.trustedFetchFn },
124
127
  ...options.transport?.allowPrivateIp !== void 0 && { allowPrivateIp: options.transport.allowPrivateIp },
125
128
  ...options.transport?.maxResponseBytes !== void 0 && {
@@ -158,13 +161,14 @@ function testClientMatchesVersionOptions(client, agentUrl, options) {
158
161
  const expectedAuthMode = authReuseMode(effectiveOptions);
159
162
  const expectedRequestScopeMode = requestScopeReuseMode(effectiveOptions);
160
163
  const expectedRequestSigningMode = requestSigningReuseMode(effectiveOptions.functional_request_signing);
164
+ const expectedOAuthStorage = effectiveOptions.auth?.type === "oauth" ? effectiveOptions.auth.storage : void 0;
161
165
  if (!meta) {
162
- return expectedRequestSigningMode === void 0 && effectiveOptions.adcpVersion === void 0 && effectiveOptions.versionEnvelope === void 0 && effectiveOptions.transport === void 0;
166
+ return expectedOAuthStorage === void 0 && expectedRequestSigningMode === void 0 && effectiveOptions.adcpVersion === void 0 && effectiveOptions.versionEnvelope === void 0 && effectiveOptions.transport === void 0;
163
167
  }
164
168
  const expectedAdcpVersion = effectiveOptions.adcpVersion ?? ADCP_VERSION;
165
169
  const expectedWireAdcpVersion = effectiveOptions.wireAdcpVersion;
166
170
  const expectedVersionEnvelope = effectiveOptions.versionEnvelope ?? "auto";
167
- return meta.agentUrl === agentUrl && meta.protocol === (effectiveOptions.protocol ?? "mcp") && meta.adcpVersion === expectedAdcpVersion && meta.wireAdcpVersion === expectedWireAdcpVersion && meta.versionEnvelope === expectedVersionEnvelope && meta.strictResponseSchemaValidation === (effectiveOptions.strictResponseSchemaValidation !== false) && meta.authMode === expectedAuthMode && meta.requestScopeMode === expectedRequestScopeMode && meta.requestSigningMode === expectedRequestSigningMode && meta.fetchFn === effectiveOptions.transport?.trustedFetchFn && meta.allowPrivateIp === effectiveOptions.transport?.allowPrivateIp && meta.maxResponseBytes === effectiveOptions.transport?.maxResponseBytes && meta.requestTimeoutMs === effectiveOptions.transport?.requestTimeoutMs && meta.legacyCompatEnabled === effectiveOptions.transport?.legacyCompat?.enabled;
171
+ return meta.agentUrl === agentUrl && meta.protocol === (effectiveOptions.protocol ?? "mcp") && meta.adcpVersion === expectedAdcpVersion && meta.wireAdcpVersion === expectedWireAdcpVersion && meta.versionEnvelope === expectedVersionEnvelope && meta.strictResponseSchemaValidation === (effectiveOptions.strictResponseSchemaValidation !== false) && meta.authMode === expectedAuthMode && meta.requestScopeMode === expectedRequestScopeMode && meta.requestSigningMode === expectedRequestSigningMode && meta.oauthStorage === expectedOAuthStorage && meta.fetchFn === effectiveOptions.transport?.trustedFetchFn && meta.allowPrivateIp === effectiveOptions.transport?.allowPrivateIp && meta.maxResponseBytes === effectiveOptions.transport?.maxResponseBytes && meta.requestTimeoutMs === effectiveOptions.transport?.requestTimeoutMs && meta.legacyCompatEnabled === effectiveOptions.transport?.legacyCompat?.enabled;
168
172
  }
169
173
  function withTestKitAuthDefaults(options) {
170
174
  if (options.auth) return options;
@@ -200,9 +204,10 @@ function requestScopeReuseMode(options) {
200
204
  Object.entries(options.headers).map(([name, value]) => [name.toLowerCase(), value]).sort(([a], [b]) => a.localeCompare(b))
201
205
  ) : void 0;
202
206
  if (!options.auth && !headers && !options.test_session_id && !options.userAgent) return void 0;
207
+ const auth = options.auth?.type === "oauth" ? { ...options.auth, storage: void 0 } : options.auth;
203
208
  return testClientScopeDisambiguator(
204
209
  JSON.stringify({
205
- auth: options.auth,
210
+ auth,
206
211
  headers,
207
212
  testSessionId: options.test_session_id,
208
213
  userAgent: options.userAgent
@@ -197,7 +197,7 @@ export interface UpstreamTrafficQueryResult {
197
197
  */
198
198
  export declare function runValidations(validations: StoryboardValidation[], context: ValidationContext): ValidationResult[];
199
199
  /** Capability semver emitted in run summaries and used for advisory expiry. */
200
- export declare const RUNNER_CAPABILITY_VERSION = "14.4.0";
200
+ export declare const RUNNER_CAPABILITY_VERSION = "15.0.0";
201
201
  /** True when a failed validation contributes to the owning step's grade. */
202
202
  export declare function validationFailsStep(result: ValidationResult): boolean;
203
203
  /**
@@ -197,7 +197,7 @@ export interface UpstreamTrafficQueryResult {
197
197
  */
198
198
  export declare function runValidations(validations: StoryboardValidation[], context: ValidationContext): ValidationResult[];
199
199
  /** Capability semver emitted in run summaries and used for advisory expiry. */
200
- export declare const RUNNER_CAPABILITY_VERSION = "14.4.0";
200
+ export declare const RUNNER_CAPABILITY_VERSION = "15.0.0";
201
201
  /** True when a failed validation contributes to the owning step's grade. */
202
202
  export declare function validationFailsStep(result: ValidationResult): boolean;
203
203
  /**
@@ -88,7 +88,7 @@ export interface TestOptions {
88
88
  * - `basic`: cleartext `username` and `password`, encoded internally.
89
89
  * - `oauth`: saved OAuth tokens (access_token + refresh_token). MCP only.
90
90
  * The library auto-refreshes on 401. Obtain tokens interactively via
91
- * `adcp --save-auth <alias> --oauth`, then pass the saved blob here for
91
+ * `adcp --save-auth <alias> <url> --oauth`, then pass the saved blob here for
92
92
  * non-interactive reuse.
93
93
  * - `oauth_client_credentials`: RFC 6749 §4.4 machine-to-machine flow.
94
94
  * The library exchanges the secret for a fresh access token before each
@@ -106,6 +106,15 @@ export interface TestOptions {
106
106
  type: 'oauth';
107
107
  tokens: import('../types/adcp.mjs').AgentOAuthTokens;
108
108
  client?: import('../types/adcp.mjs').AgentOAuthClient;
109
+ /**
110
+ * Trusted runtime storage for refreshed OAuth configuration. Bound before
111
+ * client normalization; never sent to the agent. The adapter receives
112
+ * the testing client's ID (`test`), so capture any database context or
113
+ * tenant identity in the adapter itself. Shared clients require the
114
+ * same adapter object. Persistence alone does not coordinate concurrent
115
+ * refreshes of a rotating grant.
116
+ */
117
+ storage?: import('../auth/oauth/types.mjs').OAuthConfigStorage;
109
118
  } | {
110
119
  type: 'oauth_client_credentials';
111
120
  credentials: import('../types/adcp.mjs').AgentOAuthClientCredentials;
@@ -88,7 +88,7 @@ export interface TestOptions {
88
88
  * - `basic`: cleartext `username` and `password`, encoded internally.
89
89
  * - `oauth`: saved OAuth tokens (access_token + refresh_token). MCP only.
90
90
  * The library auto-refreshes on 401. Obtain tokens interactively via
91
- * `adcp --save-auth <alias> --oauth`, then pass the saved blob here for
91
+ * `adcp --save-auth <alias> <url> --oauth`, then pass the saved blob here for
92
92
  * non-interactive reuse.
93
93
  * - `oauth_client_credentials`: RFC 6749 §4.4 machine-to-machine flow.
94
94
  * The library exchanges the secret for a fresh access token before each
@@ -106,6 +106,15 @@ export interface TestOptions {
106
106
  type: 'oauth';
107
107
  tokens: import('../types/adcp').AgentOAuthTokens;
108
108
  client?: import('../types/adcp').AgentOAuthClient;
109
+ /**
110
+ * Trusted runtime storage for refreshed OAuth configuration. Bound before
111
+ * client normalization; never sent to the agent. The adapter receives
112
+ * the testing client's ID (`test`), so capture any database context or
113
+ * tenant identity in the adapter itself. Shared clients require the
114
+ * same adapter object. Persistence alone does not coordinate concurrent
115
+ * refreshes of a rotating grant.
116
+ */
117
+ storage?: import('../auth/oauth/types').OAuthConfigStorage;
109
118
  } | {
110
119
  type: 'oauth_client_credentials';
111
120
  credentials: import('../types/adcp').AgentOAuthClientCredentials;
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * AdCP SDK library version
3
3
  */
4
- export declare const LIBRARY_VERSION = "14.4.0";
4
+ export declare const LIBRARY_VERSION = "15.0.0";
5
5
  /**
6
6
  * AdCP specification version this library is built for
7
7
  */
@@ -33,10 +33,10 @@ export type AdcpVersion = (typeof COMPATIBLE_ADCP_VERSIONS)[number];
33
33
  * Full version information
34
34
  */
35
35
  export declare const VERSION_INFO: {
36
- readonly library: "14.4.0";
36
+ readonly library: "15.0.0";
37
37
  readonly adcp: "3.2.1";
38
38
  readonly compatibleVersions: readonly ["v2.5", "v2.6", "v3", "3.0.0", "3.0", "3.0.1", "3.0.2", "3.0.3", "3.0.4", "3.0.5", "3.0.6", "3.0.7", "3.0.8", "3.0.9", "3.0.10", "3.0.11", "3.0.12", "3.0.13", "3.0.14", "3.0.15", "3.0.16", "3.0.17", "3.0.18", "3.0.19", "3.0.20", "3.0.21", "3.0.22", "3.0.23", "3.0.24", "3.0.25", "3.1.0", "3.1", "3.1.1", "3.1.2", "3.1.3", "3.1.4", "3.1.5", "3.1.6", "3.1.7", "3.1.8", "3.1.9", "3.1.10", "3.1.11", "3.1.12", "3.1.13", "3.1.14", "3.1.15", "3.1.16", "3.1.17", "3.1.18", "3.1.19", "3.1.20", "3.1.21", "3.1.22", "3.1.23", "3.1.24", "3.2.1", "3.2"];
39
- readonly generatedAt: "2026-10-06T19:00:01.077Z";
39
+ readonly generatedAt: "2026-10-06T23:38:05.170Z";
40
40
  };
41
41
  /**
42
42
  * Get the AdCP specification version this library is built for
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * AdCP SDK library version
3
3
  */
4
- export declare const LIBRARY_VERSION = "14.4.0";
4
+ export declare const LIBRARY_VERSION = "15.0.0";
5
5
  /**
6
6
  * AdCP specification version this library is built for
7
7
  */
@@ -33,10 +33,10 @@ export type AdcpVersion = (typeof COMPATIBLE_ADCP_VERSIONS)[number];
33
33
  * Full version information
34
34
  */
35
35
  export declare const VERSION_INFO: {
36
- readonly library: "14.4.0";
36
+ readonly library: "15.0.0";
37
37
  readonly adcp: "3.2.1";
38
38
  readonly compatibleVersions: readonly ["v2.5", "v2.6", "v3", "3.0.0", "3.0", "3.0.1", "3.0.2", "3.0.3", "3.0.4", "3.0.5", "3.0.6", "3.0.7", "3.0.8", "3.0.9", "3.0.10", "3.0.11", "3.0.12", "3.0.13", "3.0.14", "3.0.15", "3.0.16", "3.0.17", "3.0.18", "3.0.19", "3.0.20", "3.0.21", "3.0.22", "3.0.23", "3.0.24", "3.0.25", "3.1.0", "3.1", "3.1.1", "3.1.2", "3.1.3", "3.1.4", "3.1.5", "3.1.6", "3.1.7", "3.1.8", "3.1.9", "3.1.10", "3.1.11", "3.1.12", "3.1.13", "3.1.14", "3.1.15", "3.1.16", "3.1.17", "3.1.18", "3.1.19", "3.1.20", "3.1.21", "3.1.22", "3.1.23", "3.1.24", "3.2.1", "3.2"];
39
- readonly generatedAt: "2026-10-06T19:00:01.077Z";
39
+ readonly generatedAt: "2026-10-06T23:38:05.170Z";
40
40
  };
41
41
  /**
42
42
  * Get the AdCP specification version this library is built for
@@ -31,7 +31,7 @@ __export(version_exports, {
31
31
  toReleasePrecisionVersion: () => toReleasePrecisionVersion
32
32
  });
33
33
  module.exports = __toCommonJS(version_exports);
34
- const LIBRARY_VERSION = "14.4.0";
34
+ const LIBRARY_VERSION = "15.0.0";
35
35
  const ADCP_VERSION = "3.2.1";
36
36
  const ADCP_MAJOR_VERSION = 3;
37
37
  const COMPATIBLE_ADCP_VERSIONS = [
@@ -95,10 +95,10 @@ const COMPATIBLE_ADCP_VERSIONS = [
95
95
  "3.2"
96
96
  ];
97
97
  const VERSION_INFO = {
98
- library: "14.4.0",
98
+ library: "15.0.0",
99
99
  adcp: "3.2.1",
100
100
  compatibleVersions: COMPATIBLE_ADCP_VERSIONS,
101
- generatedAt: "2026-10-06T19:00:01.077Z"
101
+ generatedAt: "2026-10-06T23:38:05.170Z"
102
102
  };
103
103
  function getAdcpVersion() {
104
104
  return ADCP_VERSION;
@@ -1,4 +1,4 @@
1
- const LIBRARY_VERSION = "14.4.0";
1
+ const LIBRARY_VERSION = "15.0.0";
2
2
  const ADCP_VERSION = "3.2.1";
3
3
  const ADCP_MAJOR_VERSION = 3;
4
4
  const COMPATIBLE_ADCP_VERSIONS = [
@@ -62,10 +62,10 @@ const COMPATIBLE_ADCP_VERSIONS = [
62
62
  "3.2"
63
63
  ];
64
64
  const VERSION_INFO = {
65
- library: "14.4.0",
65
+ library: "15.0.0",
66
66
  adcp: "3.2.1",
67
67
  compatibleVersions: COMPATIBLE_ADCP_VERSIONS,
68
- generatedAt: "2026-10-06T19:00:01.077Z"
68
+ generatedAt: "2026-10-06T23:38:05.170Z"
69
69
  };
70
70
  function getAdcpVersion() {
71
71
  return ADCP_VERSION;
@@ -1,7 +1,7 @@
1
1
  # AdCP Type Summary
2
2
 
3
3
  > Generated at: 2026-10-06
4
- > @adcp/sdk v14.4.0
4
+ > @adcp/sdk v15.0.0
5
5
 
6
6
  Curated reference of the types that matter for using the AdCP client. For full generated types see `src/lib/types/tools.generated.ts` and `src/lib/types/core.generated.ts`.
7
7
 
@@ -41,6 +41,25 @@ if (result.success) {
41
41
 
42
42
  ## Common Use Cases
43
43
 
44
+ ### OAuth Client Credentials Configuration
45
+
46
+ `AgentOAuthClientCredentialsSchema` validates SDK configuration accepted by an API. It is available from `@adcp/sdk`, `@adcp/sdk/auth`, and `@adcp/sdk/schemas`.
47
+
48
+ ```typescript
49
+ import { AgentOAuthClientCredentialsSchema } from '@adcp/sdk/schemas';
50
+
51
+ const credentials = AgentOAuthClientCredentialsSchema.parse({
52
+ token_endpoint: 'https://auth.example.com/oauth/token',
53
+ client_id: 'client-id',
54
+ client_secret: '$ENV:ADCP_CLIENT_SECRET',
55
+ scope: 'adcp',
56
+ resource: ['https://agent.example.com'],
57
+ auth_method: 'basic',
58
+ });
59
+ ```
60
+
61
+ The schema requires a valid `token_endpoint` URL and non-empty `client_id` and `client_secret` strings. Optional fields are `scope`, `resource` (a string or string array), `audience`, and `auth_method` (`'basic'` or `'body'`). Parsing preserves `$ENV:VAR_NAME` references and leaves omitted fields unset. Token exchange resolves secrets and enforces HTTPS, URL userinfo, and private-address restrictions; this schema validates the configuration shape.
62
+
44
63
  ### API Request Validation
45
64
 
46
65
  ```typescript
@@ -0,0 +1,46 @@
1
+ # OAuth authorization-server binding
2
+
3
+ Major migration: background defaults and partial storage.
4
+
5
+ Refresh tokens/confidential clients need independently trusted `issuer` in
6
+ `AgentOAuthTokens` / `AgentOAuthClient`. Missing/mismatched bindings refuse before
7
+ secret refresh, DCR or replacement (`oauth_issuer_required` / `oauth_issuer_mismatch`).
8
+ Access-only tokens/public clients permit missing/null issuer; refresh requires it
9
+ even with valid access. Comparison tolerates one trailing slash, never different
10
+ tenant paths. Metadata follows the official asymmetric issuer-echo rule.
11
+
12
+ Recover: `adcp <alias> --clear-oauth`, then `adcp <alias> --oauth`.
13
+ Clear tokens/client/verifier/discovery, keeping URL/other auth. Each issuer may come
14
+ from trusted registration records, never PRM, unverified JWT, token-endpoint hostname
15
+ or successful requests. Upgrades cannot restore historical trust. Trust the resource
16
+ before fresh credentialless sign-in uses AS metadata; missing/mismatched returned
17
+ metadata issuer refuses.
18
+
19
+ Direct `MCPOAuthProvider` defaults to background; interactive opt-in:
20
+ `allowInteractiveAuthorization: true` (CLI factories do). Background PKCE/DCR and
21
+ token/client/all invalidation refuse (`owner_reauthorization_required`); direct
22
+ redirects retain `interactive_required`. Discovery/verifier invalidation is private
23
+ in background. Callers must authorize explicit `clearAuth`.
24
+
25
+ Adapters must retain token/client issuer and interactive PKCE/discovery. The SDK
26
+ revalidates restored discovery. File/custom adapters must BOTH preserve omitted
27
+ `oauth_tokens`, `oauth_client`, `oauth_code_verifier`, `oauth_discovery_state` AND
28
+ clear own `undefined` fields. Other fields retain backend semantics: omitted
29
+ `oauth_resource` clears in file storage. Background token/client/configured
30
+ client-credentials saves omit pending fields, preserving browser state created
31
+ during HTTP. Interactive completion clears its state; background never borrows owner PKCE.
32
+
33
+ Web stores must retain `PendingWebFlow.authorizationServerIssuer` and
34
+ `clientInformation.issuer`; restart unbound flows. Check frozen AS/current client
35
+ after metadata, before POST and before save; use the same client-bearing view at
36
+ start/callback. Explicit fresh owner flows may present a credentialless view,
37
+ stage DCR privately and reconstruct for callback. Applications provide ownership
38
+ and atomic generation replacement. No distributed refresh coordination,
39
+ grant/client CAS or spent-grant cancellation: quiesce background callers for recovery.
40
+
41
+ Custom providers must preserve issuer in getters/saves. Upstream
42
+ `ClientCredentialsProvider`, `PrivateKeyJwtProvider`, `StaticPrivateKeyJwtProvider`,
43
+ `CrossAppAccessProvider` need independent `expectedIssuer`. Direct exchange/refresh
44
+ helpers require caller binding checks (SDK web/diagnosis do them). Configured client
45
+ credentials retain the exact operator token endpoint, without PRM replacement or
46
+ credential-bearing redirects.