different-ai/openwork · error · EnterpriseMcpOAuthContractError
MCP_OAUTH_CONFIGURATION_REQUIRED
MCP_OAUTH_CONFIGURATION_REQUIRED
Error message
The OAuth authorization response cannot be validated without a bound authorization-server issuer.
What it means
validateMcpAuthorizationResponseIssuer needs an expected authorization-server issuer to bind the OAuth authorization response against. The expected issuer can come from input.expectedIssuer, the authorization-server metadata's issuer field, or stored discovery's authorizationServerUrl; if none is available, the contract cannot be enforced and MCP_OAUTH_CONFIGURATION_REQUIRED is thrown. This is a configuration gap, not a mismatch.
Source
Thrown at packages/enterprise-mcp-client/src/authorization-response.ts:52
expectedIssuer?: string | null
discoveryState?: unknown
/** Undefined means the response omitted `iss`; an empty value is present and invalid. */
responseIssuer?: string
mixUpDefense?: McpAuthorizationResponseMixUpDefense
}): McpAuthorizationResponseIssuerValidation {
const discovery = isRecord(input.discoveryState) ? input.discoveryState : undefined
const authorizationServerMetadata = isRecord(discovery?.authorizationServerMetadata)
? discovery.authorizationServerMetadata
: undefined
const resourceMetadata = isRecord(discovery?.resourceMetadata)
? discovery.resourceMetadata
: undefined
const metadataIssuer = optionalString(authorizationServerMetadata?.issuer)
const discoveryIssuer = optionalString(discovery?.authorizationServerUrl)
const expectedIssuer = input.expectedIssuer ?? metadataIssuer ?? discoveryIssuer
if (!expectedIssuer) {
throw new EnterpriseMcpOAuthContractError(
"MCP_OAUTH_CONFIGURATION_REQUIRED",
"The OAuth authorization response cannot be validated without a bound authorization-server issuer.",
)
}
const advertisedIssuers = Array.isArray(resourceMetadata?.authorization_servers)
? resourceMetadata.authorization_servers.filter((value): value is string => typeof value === "string")
: undefined
const discoveryIsBound = discoveryIssuer
? isAuthorizationServerDiscoveryBound({
authorizationServerUrl: discoveryIssuer,
authorizationServerMetadata: metadataIssuer ? { issuer: metadataIssuer } : undefined,
resourceMetadata: resourceMetadata
? {
resource: optionalString(resourceMetadata.resource),
authorization_servers: advertisedIssuers,
}
: undefined,View on GitHub (pinned to 2b7df46e8a)
Solutions
- Run authorization-server metadata discovery first and pass its issuer as input.expectedIssuer
- Ensure the stored MCP connection has a discovery record containing authorizationServerUrl before validating responses
- Pass expectedIssuer explicitly when metadata/discovery are not available
- Fix the metadata endpoint or its caching so issuer is present in authorizationServerMetadata
Example fix
// before
validateMcpAuthorizationResponseIssuer({ response, resourceMetadata }) // no issuer source
// after
const metadata = await discoverAuthorizationServerMetadata(issuerUrl)
validateMcpAuthorizationResponseIssuer({ response, resourceMetadata, expectedIssuer: metadata.issuer }) Defensive patterns
Strategy: validation
Validate before calling
function assertIssuerSource(input) {
const has = input.expectedIssuer
|| (input.authorizationServerMetadata && input.authorizationServerMetadata.issuer)
|| (input.discovery && input.discovery.authorizationServerUrl);
if (!has) throw new Error('Provide expectedIssuer, metadata.issuer, or discovery.authorizationServerUrl before validating the authorization response');
} Type guard
function hasExpectedIssuer(input: ValidationInput): input is ValidationInput & { expectedIssuer: string } {
return typeof input.expectedIssuer === 'string' && input.expectedIssuer.length > 0;
} Try / catch
try {
validateMcpAuthorizationResponseIssuer(input)
} catch (e) {
if (e instanceof EnterpriseMcpOAuthContractError && e.code === 'MCP_OAUTH_CONFIGURATION_REQUIRED') {
// run metadata discovery and retry with expectedIssuer
} else throw e
} Prevention
- Always run AS metadata discovery before processing OAuth callbacks
- Persist discovery (with authorizationServerUrl) alongside the MCP connection record
- Pass expectedIssuer explicitly when constructing validation input
- Validate metadata payloads include an issuer field
When it happens
Trigger: Calling validateMcpAuthorizationResponseIssuer (during OAuth response validation) when input.expectedIssuer is undefined, authorizationServerMetadata is absent or lacks issuer, and discovery has no authorizationServerUrl.
Common situations: Skipping server metadata discovery before processing the callback; a stored MCP connection missing its discovery record (e.g. after DB migration or partial save); constructing validation input manually without passing expectedIssuer; metadata endpoints that return a payload without an issuer field.
Related errors
- mcp_oauth_configuration_required
- MCP_OAUTH_METHOD_NOT_ALLOWED
- OpenWork-managed MCP OAuth is currently available for local
- OpenWork-managed OAuth requires a remote MCP URL.
- Authorization for ${input.connectionName} did not finish. Co
AI-assisted analysis of different-ai/openwork@2b7df46e8a (2026-09-01).
Data as JSON: /api/errors/1f1076f008a6904b.
Report an issue: GitHub.