# Configuring Logto

The MCP Gateway can use [Logto](https://logto.io/) as the identity provider
behind its downstream OAuth flow. The `mcp-logto-oauth-inbound` policy is a
Logto-friendly wrapper around the generic `mcp-oauth-inbound` policy: provide
your Logto tenant endpoint, a client ID, and a client secret, and the policy
derives the OIDC issuer, JWKS URL, and authorize and token URLs from Logto's
`/oidc` mount point.

This guide walks through the Logto 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 Logto

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

### Create a Traditional Web application

1. In the Logto Console, open **Applications** and click **Create application**.
2. Pick **Traditional Web** as the application type. (Not SPA, not Native — the
   gateway needs a confidential client with a secret.)
3. Give the application a name (for example, `Zuplo MCP Gateway`) and click
   **Create application**.
4. On the application's **Settings** tab, set **Redirect URIs** to
   `https://<gateway-host>/oauth/callback`. Add
   `http://localhost:9000/oauth/callback` for local development.
5. Save.

Note the **App ID** (= client ID) and **App secret** (= client secret) from the
application's detail page.

### Find your tenant endpoint

Open **Settings → Domains** in the Logto Console. Your default tenant endpoint
looks like `https://your-tenant.logto.app`. If you've configured a custom
domain, use that instead. The wrapper takes the origin only — no `/oidc`, no
`.well-known/...`, no trailing slash.

## Wire the policy into the gateway

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

```json
{
  "name": "logto-managed-oauth",
  "policyType": "mcp-logto-oauth-inbound",
  "handler": {
    "module": "$import(@zuplo/runtime/mcp-gateway)",
    "export": "McpLogtoOAuthInboundPolicy",
    "options": {
      "logtoEndpoint": "$env(LOGTO_ENDPOINT)",
      "clientId": "$env(LOGTO_CLIENT_ID)",
      "clientSecret": "$env(LOGTO_CLIENT_SECRET)"
    }
  }
}
```

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

Given `logtoEndpoint: "https://acme.logto.app"`:

| Generic field           | Derived value                       |
| ----------------------- | ----------------------------------- |
| `oidc.issuer`           | `https://acme.logto.app/oidc`       |
| `oidc.jwksUrl`          | `https://acme.logto.app/oidc/jwks`  |
| `browserLogin.url`      | `https://acme.logto.app/oidc/auth`  |
| `browserLogin.tokenUrl` | `https://acme.logto.app/oidc/token` |

These endpoint shapes come from Logto's OIDC provider mounted at `/oidc` and its
discovery document at
`https://<your-logto-endpoint>/oidc/.well-known/openid-configuration`.

## 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 Logto 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

- **`logtoEndpoint` rejected at boot.** The value includes `/oidc`,
  `/.well-known/openid-configuration`, or another path. Use the bare tenant
  endpoint origin.
- **`redirect_uri` rejected by Logto.** The redirect URI on the application
  doesn't match `https://<gateway-host>/oauth/callback`. Match scheme, host, and
  path.

## Related

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