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.
How it works
Section titled “How it works”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]
- 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 isdefaultwhen the service is not in a project environment) - The Keycard SDK reads the token on every request and presents it as an authentication credential to Keycard
- 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
- 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.
Prerequisites
Section titled “Prerequisites”- 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
Create the Render service
Section titled “Create the Render service”-
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 --confirmFind your Issuer URL in Keycard Console under Settings → Connection.
-
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. -
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 -
Register the production Resource
Keep the localhost Resource from the previous guide for local development. In Keycard Console, navigate to Resources → Add Resource → Add Manually and register the deployed server as a separate Resource:
Field Value Resource Name My MCP Server (Production) Resource Identifier https://<your-service>.onrender.com/mcpCredential Provider Zone Provider
Keep your server code unchanged
Section titled “Keep your server code unchanged”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.
Register the Render identity in Keycard
Section titled “Register the Render identity in Keycard”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.
-
Create a Provider for Render’s OIDC issuer
In Keycard Console, navigate to Providers → Add Provider:
Field Value Name Render OIDC Identifier https://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. -
Create the production Application
Navigate to Applications → Add 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.
-
Add a workload identity credential
On the production Application’s details page, open Credentials and add a Workload Identity credential:
Field Value Provider Render OIDC Subject workspace:<render-workspace-id>:environment:default:service:<service-id>The subject must match the
subclaim of your service’s token exactly. The environment segment isdefaultunless the service belongs to a Render project environment, in which case it is the environment’s ID (starts withevm-). A trailing*wildcard is supported if you want to trust every service in the workspace, at the cost of looser pinning. -
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_IDorKEYCARD_CLIENT_SECRETvariables to set on the service.
Verify
Section titled “Verify”-
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. -
Check the Audit Log
In Keycard Console, open the Audit Log and confirm
credentials:issueevents show the production Application authenticating with no client secret involved.
Troubleshooting
Section titled “Troubleshooting”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:
render ssh <service-id>cut -d. -f2 "$AWS_WEB_IDENTITY_TOKEN_FILE" | base64 -dConfirm the iss and sub values match the Provider identifier and credential subject you registered.
AWS_WEB_IDENTITY_TOKEN_FILE is not set
Section titled “AWS_WEB_IDENTITY_TOKEN_FILE is not set”- Confirm
AWS_ROLE_ARNis 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_IDandKEYCARD_CLIENT_SECRETare 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/mcpexactly
Dockerfile-based builds
Section titled “Dockerfile-based builds”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.
What’s next
Section titled “What’s next”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.
- Act on Behalf of Absent Users: run background work from the deployed server after a one-time user consent
- Audit Log & Sessions: monitor every credential the production Application is issued
- Deploy an MCP server on Cloudflare Workers: an alternative deployment target with its own credential options