Skip to content

Decouple OAuth issuer and MCP resource URLs for tunnel/proxy deployments #182

Description

@xiepixie

Environment & Context

When connecting DevSpace to ChatGPT through OpenAI's official Secure MCP Tunnel, ChatGPT accesses the MCP server through an OpenAI-hosted tunnel resource, while DevSpace's OAuth Authorization Server may remain hosted at a separate public HTTPS origin.

In this setup, the OAuth Authorization Server origin and the externally visible MCP Resource URI are intentionally different.

Problem

DevSpace currently derives both its OAuth Authorization Server configuration and its MCP resource identity from publicBaseUrl.

In SingleUserOAuthProvider (oauth-provider.ts), authorization and token exchange validate the requested OAuth resource using @modelcontextprotocol/sdk's checkResourceAllowed.

The /mcp route in server.ts performs the same resource validation when checking the bearer token.

checkResourceAllowed requires the requested and configured resources to have the same origin.

This works when DevSpace itself is exposed directly at publicBaseUrl, but fails when the externally visible MCP resource is an OpenAI Secure MCP Tunnel endpoint while the OAuth Authorization Server remains at another origin.

For example:

OAuth Authorization Server:
https://devspace.example.com

MCP Resource:
<OpenAI-hosted Secure MCP Tunnel endpoint>

The resulting resource mismatch causes authorization/token exchange failures such as:

Invalid or missing OAuth resource

and subsequent MCP requests may fail with:

401 Unauthorized

This prevents DevSpace's current OAuth implementation from working cleanly with OpenAI Secure MCP Tunnel without modifying the server.

Proposed Solution

Decouple the OAuth Authorization Server URL from the accepted MCP Resource URI(s).

For example, DevSpace could support an explicit configuration such as:

DEVSPACE_PUBLIC_BASE_URL=https://devspace.example.com
DEVSPACE_OAUTH_ALLOWED_RESOURCE_URLS=https://<exact-tunnel-resource>

or equivalent structured configuration.

The existing publicBaseUrl behavior could remain the default for backward compatibility. When additional resource URLs are configured, authorization, token exchange, refresh-token handling, and /mcp bearer-token validation would all validate against the same explicit allowlist.

I would prefer explicit resource URIs rather than trusting broad gateway domains, so OAuth audience/resource binding remains narrowly scoped.

Why this helps

This would support deployments where:

OAuth / browser-facing endpoints
ChatGPT → public HTTPS endpoint → DevSpace OAuth endpoints

High-frequency MCP traffic
ChatGPT → OpenAI Secure MCP Tunnel → tunnel-client → 127.0.0.1 → DevSpace /mcp

The OAuth Authorization Server can remain publicly reachable as required for the browser-facing OAuth flow, while the MCP server itself remains private and high-frequency tool traffic uses Secure MCP Tunnel.

It would also make DevSpace compatible with other reverse-proxy or gateway deployments where the OAuth issuer and externally visible MCP resource intentionally use different origins.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions