ZuploZuplo
LoginSign Up
  • Documentation
  • API Reference
Introduction
Getting Started
    Develop using the Portal
      1 - Setup Your Gateway2 - Rate Limiting3 - API Key Auth4 - Deploy5 - Dynamic Rate LimitingMCP - Quick start
    Develop Locally
      1 - Setup Your Gateway2 - Rate Limiting3 - API Key Auth
Concepts
Development
Policies
Handlers
API Keys
MCP Server
MCP Gateway
    IntroductionBetaQuickstartQuickstart (Local Dev)How it works
    Connect MCP clients
    Authentication
      OverviewUpstream OAuthConnect an upstream OAuth provider
      Identity providers
        Auth0Amazon CognitoClerkMicrosoft EntraGoogleKeycloakLogtoOktaOneLoginPingOneWorkOSGeneric OIDC
      Manual OAuth testing
    Configuration
    Observability
    ReferenceTroubleshooting
AI Gateway
Developer Portal
Monetization
Deploying & Source Control
Observability
Networking & Infrastructure
Account Management
Programming API
Build with AI
Zuplo CLI
Migration Guides
Platform LimitsSecuritySupportTrust & ComplianceChangelog
powered by Zudoku
Identity providers

Configuring Keycloak

The MCP Gateway can use Keycloak as the identity provider behind its downstream OAuth flow. The mcp-keycloak-oauth-inbound policy is a Keycloak-friendly wrapper around the generic mcp-oauth-inbound policy: provide your Keycloak base URL, a realm name, a client ID, and a client secret, and the policy derives the realm-issuer URL, JWKS URL, and authorize and token URLs from Keycloak's standard OpenID Connect endpoint layout.

This guide walks through the Keycloak admin console setup, then wires the policy into a gateway project. Read the authentication overview first for the two-layer OAuth model.

Set up Keycloak

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

Create a client in the realm

  1. In the Keycloak admin console, switch to the realm you want the gateway to use.
  2. Open Clients and click Create client.
  3. Give the client a Client ID (for example, zuplo-mcp-gateway) and click Next.
  4. Enable Client authentication (so the client requires a secret) and leave Standard flow (authorization code) enabled. Disable Service accounts roles and Direct access grants — the gateway only needs the browser code flow.
  5. Click Next.
  6. Set Valid redirect URIs to https://<gateway-host>/oauth/callback. Add http://localhost:9000/oauth/callback for local development.
  7. Set Web origins to https://<gateway-host> (and http://localhost:9000 for local dev).
  8. Click Save.

Note the client credentials

Open the client's Credentials tab. Copy the Client secret. The Client ID is the value you set above.

Wire the policy into the gateway

Add the policy to config/policies.json:

Code
{ "name": "keycloak-managed-oauth", "policyType": "mcp-keycloak-oauth-inbound", "handler": { "module": "$import(@zuplo/runtime/mcp-gateway)", "export": "McpKeycloakOAuthInboundPolicy", "options": { "keycloakBaseUrl": "$env(KEYCLOAK_BASE_URL)", "realm": "$env(KEYCLOAK_REALM)", "clientId": "$env(KEYCLOAK_CLIENT_ID)", "clientSecret": "$env(KEYCLOAK_CLIENT_SECRET)" } } }

keycloakBaseUrl is the Keycloak server root, without /realms/{realm} — set the realm separately on the realm option. If your deployment uses a path prefix (legacy /auth), include that in keycloakBaseUrl (https://sso.example.com/auth).

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 for the route and plugin patterns — they're identical across all wrappers).

What the wrapper derives

Given keycloakBaseUrl: "https://sso.example.com" and realm: "customer-portal":

Generic fieldDerived value
oidc.issuerhttps://sso.example.com/realms/customer-portal
oidc.jwksUrlhttps://sso.example.com/realms/customer-portal/protocol/openid-connect/certs
browserLogin.urlhttps://sso.example.com/realms/customer-portal/protocol/openid-connect/auth
browserLogin.tokenUrlhttps://sso.example.com/realms/customer-portal/protocol/openid-connect/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 Keycloak 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 — it exercises every endpoint with curl so you can see the raw responses.

Common issues

  • keycloakBaseUrl rejected at boot. The value includes /realms/.... Strip the realm path; pass the realm name on the realm option instead.
  • Invalid redirect_uri from Keycloak. The callback URL on the client doesn't match https://<gateway-host>/oauth/callback.
  • Invalid client credentials. The client isn't a confidential client (Client authentication off), or the secret value doesn't match. Re-copy the secret from the Credentials tab.

Related

  • Authentication overview
  • Configuring a generic OIDC provider
  • Per-user OAuth to upstream MCP servers
Edit this page
Last modified on May 27, 2026
GoogleLogto
On this page
  • Set up Keycloak
    • Create a client in the realm
    • Note the client credentials
  • Wire the policy into the gateway
  • What the wrapper derives
  • Test the configuration
  • Common issues
  • Related
JSON