Skip to content
API Reference
Guides
Use Keycard SDKs

Deploy to Render without Secrets

Deploy an MCP server on Render using managed OIDC workload identity instead of a client secret

You built an MCP server that calls external APIs on behalf of users. Now you want to run it in production without copying a KEYCARD_CLIENT_SECRET into your hosting platform: a long-lived secret that can leak, needs rotation, and grants whoever holds it your Application’s full identity.

Render’s managed OIDC removes that secret entirely. Render mints a short-lived, automatically rotated identity token for each service, and Keycard accepts that token as your Application’s credential through workload identity federation. Your service proves who it is with its runtime identity. There is no secret to provision, store, or rotate.

flowchart LR
    A[Render] -->|"Mounts rotating OIDC token"| B[Your MCP Server]
    B -->|"Token exchange + client assertion"| C[Keycard]
    C -->|"Verify issuer + subject"| C
    C -->|"Delegated API token"| B
    B -->|"Bearer token"| D[External API]
  1. Render issues a short-lived OIDC token for your service and rotates it automatically. The token’s issuer is https://oidc.render.com/<render-workspace-id> and its subject identifies your exact service: workspace:<render-workspace-id>:environment:<environment-id>:service:<service-id> (the environment segment is default when the service is not in a project environment)
  2. The Keycard SDK reads the token on every request and presents it as an authentication credential to Keycard
  3. Keycard verifies the token’s signature against Render’s published keys, then matches the issuer and subject against the workload identity credential registered on your Application
  4. Token exchange proceeds exactly as before: your tools receive delegated, per-user API tokens

Because Keycard pins the credential to your service’s exact subject, no other service, even in the same Render workspace, can authenticate as your Application.

  • Render workspace on a Pro plan or higher (required for managed OIDC), with the Render CLI installed and logged in
  • Completed the Call External APIs from MCP guide: a working MCP server with delegated access and an Application in Keycard Console
  • Your MCP server code in a Git repository that Render can access
  1. Deploy the service

    Terminal window
    render services create \
    --name my-mcp-server \
    --type web_service \
    --repo <your-repo-url> \
    --branch main \
    --runtime python \
    --build-command "uv sync --frozen" \
    --start-command "uv run my-mcp-server" \
    --env-var PORT=10000 \
    --env-var KEYCARD_ISSUER=<keycard-issuer-url> \
    --env-var AWS_ROLE_ARN=keycard-oidc-trigger \
    -o json --confirm

    Find your Issuer URL in Keycard Console under SettingsConnection.

  2. Note the service ID and URL

    The create command returns the service ID (starts with srv-) and the public URL (https://<your-service>.onrender.com). You need both in the next sections.

  3. Set your server’s public URL

    In the Render dashboard, add an environment variable to the service. This step uses the dashboard because the public URL only exists after creation, and the CLI’s update command does not manage environment variables:

    Terminal window
    MCP_SERVER_URL=https://<your-service>.onrender.com/mcp
  4. Register the production Resource

    Keep the localhost Resource from the previous guide for local development. In Keycard Console, navigate to ResourcesAdd ResourceAdd Manually and register the deployed server as a separate Resource:

    FieldValue
    Resource NameMy MCP Server (Production)
    Resource Identifierhttps://<your-service>.onrender.com/mcp
    Credential ProviderZone Provider

No code change is required. One codebase serves both environments because the SDK selects the Application credential from the environment. Locally, KEYCARD_CLIENT_ID and KEYCARD_CLIENT_SECRET select your local Application’s client secret. On Render, those variables are absent, so the SDK discovers AWS_WEB_IDENTITY_TOKEN_FILE and authenticates as the production Application with the token it points to.

Your AuthProvider from the previous guide works unchanged:

import os
from keycardai.fastmcp import AuthProvider
auth_provider = AuthProvider(
zone_url=os.environ["KEYCARD_ISSUER"],
mcp_server_url=os.environ["MCP_SERVER_URL"],
)

The token is re-read on every request, so Render’s automatic rotation requires no handling in your code.

Rather than reusing the Application from the previous guide, create a second Application dedicated to the deployment. Each environment gets its own identity, its own dependencies, and its own audit attribution, and revoking one never touches the other.

  1. Create a Provider for Render’s OIDC issuer

    In Keycard Console, navigate to ProvidersAdd Provider:

    FieldValue
    NameRender OIDC
    Identifierhttps://oidc.render.com/<render-workspace-id>

    Your Render workspace ID starts with tea- and is shown at the top of the workspace’s Settings page in the Render dashboard. Keycard discovers Render’s signing keys from the issuer automatically.

  2. Create the production Application

    Navigate to ApplicationsAdd Application, name it (for example, My MCP Server Production), and click Create Application.

    Then, on the Application details page:

    • On the Provides tab, click Add provided resource and select the production Resource you registered earlier.
    • On the Dependencies tab, click Add dependency and select the same external API Resource(s) your local Application depends on.

    Do not generate client credentials for this Application. The next step gives it a credential that never needs storing.

  3. Add a workload identity credential

    On the production Application’s details page, open Credentials and add a Workload Identity credential:

    FieldValue
    ProviderRender OIDC
    Subjectworkspace:<render-workspace-id>:environment:default:service:<service-id>

    The subject must match the sub claim of your service’s token exactly. The environment segment is default unless the service belongs to a Render project environment, in which case it is the environment’s ID (starts with evm-). A trailing * wildcard is supported if you want to trust every service in the workspace, at the cost of looser pinning.

  4. Redeploy the service

    Trigger a deploy so the service starts with the OIDC token mounted. Because the production Application authenticates only through workload identity, there are no KEYCARD_CLIENT_ID or KEYCARD_CLIENT_SECRET variables to set on the service.

  1. Call a tool end to end

    Connect an MCP client to https://<your-service>.onrender.com/mcp, complete the sign-in flow, and invoke a tool that calls the external API.

  2. Check the Audit Log

    In Keycard Console, open the Audit Log and confirm credentials:issue events show the production Application authenticating with no client secret involved.

invalid_client: No token application credential configured

Section titled “invalid_client: No token application credential configured”

The error message includes the exact Provider issuer and subject Keycard extracted from your service’s token. Compare them against the Provider identifier and credential subject in Keycard Console. The subject must match character for character, including the service ID.

To inspect the token Render actually issued, SSH into the service and decode its claims:

Terminal window
render ssh <service-id>
cut -d. -f2 "$AWS_WEB_IDENTITY_TOKEN_FILE" | base64 -d

Confirm the iss and sub values match the Provider identifier and credential subject you registered.

  • Confirm AWS_ROLE_ARN is set on the service and redeploy, since Render mounts the token during deploys
  • Managed OIDC requires a Pro workspace or higher

Token exchange fails on Render but works locally

Section titled “Token exchange fails on Render but works locally”
  • Confirm KEYCARD_CLIENT_ID and KEYCARD_CLIENT_SECRET are not set on the service: a client secret takes priority over workload identity, so the service would authenticate as your local Application
  • Verify the external API Resource is a Dependency on the production Application, not only on the local one
  • Verify the production Resource’s Resource Identifier matches https://<your-service>.onrender.com/mcp exactly

Render does not provide the OIDC token at build time for services built from a Dockerfile. The token is available at runtime either way; if you need OIDC during builds, use a native runtime.

Your MCP server is running in production with no stored Keycard credential. From here you can extend what the deployed server does and watch how it is used.