> ## Documentation Index
> Fetch the complete documentation index at: https://docs.mcp-use.com/llms.txt
> Use this file to discover all available pages before exploring further.

# OAuth Proxy

> Bridge OAuth providers without Dynamic Client Registration to a TypeScript MCP server.

Use `oauthProxy` when an identity provider cannot register MCP clients dynamically. You register one application in the provider dashboard, store its client credentials on the MCP server, and let the server mediate authorization and token exchange for MCP clients.

If your provider supports Dynamic Client Registration, use a built-in provider or [Custom Provider](/typescript/server/authentication/providers/custom). In DCR mode, clients register directly with the upstream provider and the MCP server only verifies tokens.

This guide covers the proxy workflow. Use the [auth providers API reference](/typescript/api-reference/server/auth-providers#oauthproxy) for exact `oauthProxy()` options, defaults, payload contracts, and verifier behavior.

## Use OAuth Proxy only when DCR is unavailable

OAuth Proxy is the right fit when all of these are true:

* The provider gives you a fixed `clientId` and `clientSecret`.
* The provider does not expose a `registration_endpoint` in OAuth metadata.
* You can safely store the client secret on the MCP server.
* You are comfortable with the MCP server brokering the OAuth callback and token exchange.

Common proxy targets include Google, GitHub, Okta, Microsoft Entra ID, and enterprise SSO deployments that require pre-registered applications.

## Register one upstream redirect URI

In the provider dashboard, register the MCP server callback URL:

```text theme={null}
http://localhost:3000/oauth/callback
```

Use your deployed server domain in production:

```text theme={null}
https://mcp.example.com/oauth/callback
```

Do not register every MCP client's redirect URI with the upstream provider. The MCP server brokers the callback for clients.

## Configure the proxy

This Google example validates opaque user access tokens with Google's tokeninfo and userinfo endpoints.

```typescript theme={null}
import { MCPServer, oauthProxy } from "mcp-use/server";

const server = new MCPServer({
  name: "google-proxy-server",
  version: "1.0.0",
  oauth: oauthProxy({
    authEndpoint: "https://accounts.google.com/o/oauth2/v2/auth",
    tokenEndpoint: "https://oauth2.googleapis.com/token",
    issuer: "https://accounts.google.com",
    clientId: process.env.GOOGLE_CLIENT_ID!,
    clientSecret: process.env.GOOGLE_CLIENT_SECRET!,
    scopes: ["openid", "email", "profile"],
    extraAuthorizeParams: { access_type: "offline" },
    async verifyToken(token) {
      const tokenInfoResponse = await fetch(
        `https://www.googleapis.com/oauth2/v3/tokeninfo?access_token=${encodeURIComponent(token)}`,
      );

      if (!tokenInfoResponse.ok) {
        throw new Error("Invalid Google access token");
      }

      const tokenInfo = (await tokenInfoResponse.json()) as Record<string, unknown>;

      if (tokenInfo.aud !== process.env.GOOGLE_CLIENT_ID) {
        throw new Error("Google token audience did not match this client");
      }

      const userInfoResponse = await fetch("https://openidconnect.googleapis.com/v1/userinfo", {
        headers: { Authorization: `Bearer ${token}` },
      });

      if (!userInfoResponse.ok) {
        throw new Error("Failed to fetch Google userinfo");
      }

      const userInfo = (await userInfoResponse.json()) as Record<string, unknown>;
      return { payload: { ...tokenInfo, ...userInfo } };
    },
  }),
});

await server.listen(3000);
```

Use `jwksVerifier` only for providers that issue JWT access tokens and publish a JWKS. Write a custom `verifyToken` function for opaque-token providers.

## Understand the proxy flow

In proxy mode, the MCP server acts as the OAuth-facing server for MCP clients.

1. The MCP client calls the MCP server's `/register` endpoint.
2. The MCP server returns the pre-registered upstream `clientId`.
3. The client starts PKCE authorization through the MCP server's `/authorize` endpoint.
4. The upstream provider redirects to the MCP server's `/oauth/callback`.
5. The MCP server forwards the authorization code to the client's original redirect URI.
6. During token exchange, the MCP server injects the upstream `clientId` and `clientSecret`.
7. The client calls `/mcp/*` with the upstream access token.
8. The MCP server verifies the token with your `verifyToken` function.

The proxy passes upstream tokens through. It does not mint its own access tokens.

## Handle opaque tokens

GitHub issues opaque access tokens, so `jwksVerifier` does not apply. Validate the token by calling the provider API.

```typescript theme={null}
oauth: oauthProxy({
  authEndpoint: "https://github.com/login/oauth/authorize",
  tokenEndpoint: "https://github.com/login/oauth/access_token",
  issuer: "https://github.com",
  clientId: process.env.GITHUB_CLIENT_ID!,
  clientSecret: process.env.GITHUB_CLIENT_SECRET!,
  scopes: ["read:user", "user:email"],
  async verifyToken(token) {
    const response = await fetch("https://api.github.com/user", {
      headers: {
        Authorization: `Bearer ${token}`,
        "User-Agent": "my-mcp-server",
      },
    });

    if (!response.ok) {
      throw new Error("Invalid GitHub token");
    }

    const user = await response.json();
    return { payload: { sub: String(user.id), ...user } };
  },
  getUserInfo(payload) {
    return {
      userId: payload.sub as string,
      username: payload.login as string | undefined,
      name: payload.name as string | undefined,
      email: payload.email as string | undefined,
      picture: payload.avatar_url as string | undefined,
    };
  },
});
```

## Use upstream tokens in tools

The upstream access token is available as `ctx.auth.accessToken`. Use it only when a tool must call the provider API on behalf of the user.

```typescript theme={null}
import { error, object } from "mcp-use/server";

server.tool(
  {
    name: "get_google_profile",
    description: "Fetch the caller's Google profile.",
  },
  async (_args, ctx) => {
    if (!ctx.auth) {
      return error("Unauthorized");
    }

    const response = await fetch("https://openidconnect.googleapis.com/v1/userinfo", {
      headers: { Authorization: `Bearer ${ctx.auth.accessToken}` },
    });

    return object(await response.json());
  },
);
```

## Next steps

<CardGroup cols={2}>
  <Card title="Custom Provider" icon="code" href="/typescript/server/authentication/providers/custom">
    Use a provider that supports Dynamic Client Registration.
  </Card>

  <Card title="User Context" icon="user" href="/typescript/server/authentication/user-context">
    Use proxied identity data inside tools.
  </Card>

  <Card title="OAuth Proxy API reference" icon="terminal" href="/typescript/api-reference/server/auth-providers#oauthproxy">
    Look up exact proxy options, defaults, and verifier contracts.
  </Card>

  <Card title="PKCE" icon="book-open" href="https://datatracker.ietf.org/doc/html/rfc7636">
    Review the authorization-code security flow used by MCP clients.
  </Card>
</CardGroup>
