different-ai/openwork · error

An enterprise MCP OAuth redirect URI cannot contain credenti

Error message

An enterprise MCP OAuth redirect URI cannot contain credentials or a fragment.

What it means

validateRedirectUri in packages/enterprise-mcp-client/src/enterprise-mcp-client.ts throws when the redirect URI contains embedded userinfo credentials (username/password) or a fragment. Both are invalid for OAuth redirect URIs per RFC 9700 (fragments never reach the server; credentials in URLs leak secrets) and would break exact-match registration at the authorization server.

Source

Thrown at packages/enterprise-mcp-client/src/enterprise-mcp-client.ts:121

  const url = new URL(parsed.serverUrl)
  if (url.protocol !== "https:" && url.protocol !== "http:") {
    throw new Error("An enterprise MCP server URL must use HTTP or HTTPS.")
  }
  if (url.username || url.password) {
    throw new Error("An enterprise MCP server URL cannot contain embedded credentials.")
  }
  if (url.hash) throw new Error("An enterprise MCP server URL cannot contain a fragment.")
  return url
}

function validateRedirectUri(redirectUri: string): string {
  const parsed = redirectUriSchema.parse(redirectUri)
  const url = new URL(parsed)
  if (url.protocol !== "https:" && url.protocol !== "http:") {
    throw new Error("An enterprise MCP OAuth redirect URI must use HTTP or HTTPS.")
  }
  if (url.username || url.password || url.hash) {
    throw new Error("An enterprise MCP OAuth redirect URI cannot contain credentials or a fragment.")
  }
  return parsed
}

function configurationValue<T>(parse: () => T): T {
  try {
    return parse()
  } catch (error) {
    throw new EnterpriseMcpClientError({
      operationPhase: "configuration",
      requestPhase: null,
      cause: error,
    })
  }
}

async function closeWithinDeadline(close: () => Promise<void>, timeoutMs: number): Promise<void> {
  let timer: ReturnType<typeof setTimeout> | undefined

View on GitHub (pinned to 2b7df46e8a)

Solutions

  1. Remove any user:pass@ userinfo and #fragment from the redirect URI.
  2. Register a clean https:// (or http://127.0.0.1 loopback) callback with the authorization server and use exactly that string.
  3. Validate the redirect URI shape before constructing the client.

Example fix

// before
redirectUri: "https://admin:secret@mcp.example.com/callback#oauth"

// after
redirectUri: "https://mcp.example.com/callback"
Defensive patterns

Strategy: validation

Validate before calling

function assertCleanRedirectUri(redirectUri: string) {
  const u = new URL(redirectUri)
  if (u.username || u.password || u.hash) {
    throw new Error("redirectUri must not contain credentials or a fragment")
  }
}

Prevention

When it happens

Trigger: Passing a redirect URI like "https://user:pass@example.com/cb" or "https://example.com/cb#frag" to the client's redirect URI configuration.

Common situations: Reusing a URL copied from a browser (with an anchor) as the redirect; template config values like https://USER:PASS@host/cb that were never substituted out; confusion between the server URL rules and redirect URI rules.

Related errors


AI-assisted analysis of different-ai/openwork@2b7df46e8a (2026-09-01). Data as JSON: /api/errors/b5e8e223841f9cf2. Report an issue: GitHub.