#WorkOS MCP Authkit conenction iss

4 messages · Page 1 of 1 (latest)

muted sluice
#

Hi all!!
I’m building a Streamable HTTP MCP server protected by WorkOS AuthKit MCP auth, and I’m connecting to it from Warp Desktop.

Server URL:
http://localhost:3001/mcp (currently working locally)

WorkOS config:
Dynamic Client Registration: enabled
Client ID Metadata Document: enabled
MCP Resource Indicator: http://localhost:3001/mcp
Redirect URI: warp://mcp/oauth2callback

My MCP server exposes protected resource metadata and an authorization server metadata proxy:
/.well-known/oauth-protected-resource
/.well-known/oauth-protected-resource/mcp
/.well-known/oauth-authorization-server
/.well-known/oauth-authorization-server/mcp

The protected resource metadata returns:

{
  "resource": "http://localhost:3001/mcp",
  "authorization_servers": ["https://<my-authkit-domain>.authkit.app"],
  "scopes_supported": ["openid", "profile", "email"]
}

According to the WorkOS MCP docs, the MCP client should send the configured resource indicator during OAuth, and the access token should have:
aud = http://localhost:3001/mcp

But when Warp finishes OAuth and calls my MCP endpoint, the token has:
aud = client_<workos_client_id>

So strict JWT verification with:

jwtVerify(token, jwks, {
  issuer: "https://<my-authkit-domain>.authkit.app",
  audience: "http://localhost:3001/mcp",
})

fails with an audience mismatch. Warp then reports:

MCP: preflight connection to MCP server failed:
Transport creation error: Unexpected status code: 401 Unauthorized

The workaround that makes it connect is to allowlist the WorkOS client id as an additional accepted audience:
MCP_ALLOWED_TOKEN_AUDIENCES=client_<workos_client_id>

Then the server accepts both:
http://localhost:3001/mcp
client_<workos_client_id>

My question:
Is Warp expected to request WorkOS MCP access tokens with aud=client_<id> instead of the configured MCP Resource Indicator? Or should Warp be sending the resource=http://localhost:3001/mcp parameter so WorkOS mints a resource-audience token?

fickle heathBOT
#

Hi @muted sluice. I'm kapa.ai, your friendly support bot. I will try to answer your question by searching through the knowledge base. :wave:

#

This is directly related to a known open bug in Warp.

Root Cause: Missing RFC 8707 resource Parameter

Warp's pinned rmcp dependency omits the resource parameter (RFC 8707 — Resource Indicators for OAuth 2.0) from both the /authorize URL and the /token exchange request. [GitHub Issue #9462]

This is exactly why your token has aud = client_<workos_client_id> instead of aud = <http://localhost:3001/mcp> — because Warp never sends resource=<http://localhost:3001/mcp> to WorkOS during the OAuth flow. Without that parameter, WorkOS has no instruction to mint a resource-audience token, so it falls back to issuing a token scoped to the client ID.

The fix requires adding the resource parameter to both the authorize URL and token exchange, like so:

let mut auth_request = oauth_client
    .authorize_url(CsrfToken::new_random)
    .set_pkce_challenge(pkce_challenge)
    .add_extra_param("resource", self.base_url.to_string());

and similarly on .exchange_code(...).set_pkce_verifier(...).add_extra_param("resource", self.base_url.to_string()). [GitHub Issue #9462]

Current Status

  • A fix PR is open against Warp's rmcp fork: warpdotdev/rmcp#10
  • Once that lands, Warp needs to bump its pinned rmcp revision in Cargo.toml
  • The issue is tracked as open and actionable [GitHub Issue #9462]

Your Workaround is Correct (for Now)

Allowlisting client_<workos_client_id> as an additional accepted audience is the right short-term workaround until Warp ships the RFC 8707 fix. Your diagnosis is accurate — this is a Warp bug, not a misconfiguration on your end.

#

You may want to +1 or comment on issue #9462 to help signal priority to the Warp team.

Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: