# Configuring Google

The MCP Gateway can use Google as the identity provider behind its downstream
OAuth flow. The `mcp-google-oauth-inbound` policy is a Google-friendly wrapper
around the generic `mcp-oauth-inbound` policy: provide a Google OAuth client ID
and client secret, and the policy uses Google's fixed OIDC issuer
(`https://accounts.google.com`) and discovery document automatically.

This guide walks through the Google Cloud Console setup, then wires the policy
into a gateway project. Read the [authentication overview](./overview.mdx) first
for the two-layer OAuth model.

## Set up Google

The MCP Gateway acts as an OAuth 2.1 authorization server in front of Google.
Google handles browser login; the gateway issues its own access tokens that bind
to MCP routes.

### Create an OAuth client

1. In the Google Cloud Console, switch to the project that should own the OAuth
   client, then open **APIs & Services → Credentials**.
2. Click **Create credentials → OAuth client ID**. (If prompted, configure the
   **OAuth consent screen** first — pick **Internal** for Google Workspace
   tenants or **External** for general use, then add the user types you want to
   allow.)
3. Choose **Web application** as the application type.
4. Give the client a name (for example, `Zuplo MCP Gateway`).
5. Under **Authorized redirect URIs**, add
   `https://<gateway-host>/oauth/callback`. Add
   `http://localhost:9000/oauth/callback` for local development with
   `zuplo dev`.
6. Click **Create**.

Note the **Client ID** (looks like
`123456789012-abc123def456.apps.googleusercontent.com`) and the **Client
secret** from the dialog. The wrapper rejects values that aren't in Google's
OAuth client ID shape.

## Wire the policy into the gateway

Add the policy to `config/policies.json`:

```json
{
  "name": "google-managed-oauth",
  "policyType": "mcp-google-oauth-inbound",
  "handler": {
    "module": "$import(@zuplo/runtime/mcp-gateway)",
    "export": "McpGoogleOAuthInboundPolicy",
    "options": {
      "clientId": "$env(GOOGLE_CLIENT_ID)",
      "clientSecret": "$env(GOOGLE_CLIENT_SECRET)"
    }
  }
}
```

Set the two environment variables in your project's environment configuration.
The secret values belong in the project secret store.

Attach the policy to each MCP route in `config/routes.oas.json` and register the
gateway plugin in `modules/zuplo.runtime.ts` (see
[Configuring Auth0](./configuring-auth0.mdx#wire-the-policy-into-the-gateway)
for the route and plugin patterns — they're identical across all wrappers).

## What the wrapper derives

Google publishes a fixed OIDC discovery document at
`https://accounts.google.com/.well-known/openid-configuration`. The wrapper
hard-codes the corresponding endpoints:

| Generic field           | Derived value                                  |
| ----------------------- | ---------------------------------------------- |
| `oidc.issuer`           | `https://accounts.google.com`                  |
| `oidc.jwksUrl`          | `https://www.googleapis.com/oauth2/v3/certs`   |
| `browserLogin.url`      | `https://accounts.google.com/o/oauth2/v2/auth` |
| `browserLogin.tokenUrl` | `https://oauth2.googleapis.com/token`          |

## Test the configuration

The fastest sanity check is to connect an MCP client:

1. Open Claude Desktop, Cursor, Claude Code, or another OAuth-aware MCP client.
2. Add a remote MCP server pointing at one of your `/mcp/{slug}` routes.
3. The client should redirect you to the Google sign-in page. After login, the
   gateway's consent screen renders. Approve it.
4. The client receives an access token and can call `tools/list`.

If something fails partway through, walk the flow manually using the
[manual OAuth testing guide](./manual-oauth-testing.mdx) — it exercises every
endpoint with `curl` so you can see the raw responses.

## Common issues

- **`clientId` rejected at boot.** The wrapper rejects values that don't use
  Google's OAuth client ID shape — issuer URLs, API hostnames, project numbers.
  Use the full `123456789012-abc123def456.apps.googleusercontent.com` form.
- **`redirect_uri_mismatch` from Google.** The redirect URI on the OAuth client
  doesn't match `https://<gateway-host>/oauth/callback` exactly. Match scheme,
  host, and path.
- **`access_denied` for Google Workspace users.** The OAuth consent screen is
  set to **Internal** but the user belongs to a different workspace, or the user
  isn't on the **Test users** list during pre-verification.

## Related

- [Authentication overview](./overview.mdx)
- [Configuring a generic OIDC provider](./configuring-generic-oidc.mdx)
- [Per-user OAuth to upstream MCP servers](./upstream-oauth.mdx)
