Authentication and authorization
This guide shows you how to secure your MCP servers using OAuth-based authentication and Cedar-based authorization policies with the ToolHive CLI.
Authentication and authorization are emerging capabilities in the MCP ecosystem. The official MCP authorization specification is still evolving, and client support for these features is limited. ToolHive is leading the way in implementing these capabilities, but you may encounter some limitations with certain clients.
Prerequisites
Before you begin, make sure you have:
- ToolHive installed and working
- Basic familiarity with OAuth, OIDC, and JWT concepts
- An identity provider that supports OpenID Connect (OIDC), such as Google, GitHub, Microsoft Entra ID (Azure AD), Okta, Auth0, or Kubernetes (for service accounts)
From your identity provider, you'll need:
- Client ID
- Audience value
- Issuer URL
- JWKS URL (for key verification)
ToolHive uses OIDC to connect to your existing identity provider, so you can authenticate with your own credentials (for example, Google login) or with service account tokens (for example, in Kubernetes). ToolHive never sees your password, only signed tokens from your identity provider.
For background on authentication, authorization, and Cedar policy examples, see Authentication and authorization framework.
Set up authentication
Step 1: Gather OIDC configuration
First, collect the necessary information from your identity provider:
- Client ID
- Audience value
- Issuer URL
- JWKS URL (for key verification)
Step 2: Run an MCP server with authentication
Use the following command to start an MCP server with authentication enabled:
thv run \
--oidc-audience <your-audience> \
--oidc-client-id <your-client-id> \
--oidc-issuer <https://your-oidc-issuer.com> \
--oidc-jwks-url <https://your-oidc-issuer.com/path/to/jwks> \
<server-name>
Replace the placeholders with your actual OIDC configuration.
Step 3: Test authentication
Once your server is running with authentication enabled, clients must include a
valid JWT (JSON Web Token) in the Authorization
header of each HTTP request.
The token should:
- Be issued by your configured identity provider
- Include the correct audience claim
- Not be expired
- Have a valid signature
:::note Client support limitations
Client support for authentication is limited at this time. While some clients support HTTP headers with SSE MCP client configurations, we do not recommend passing JWT tokens in this way since it requires manual configuration and exposes your token in plain text.
We are working on a solution within ToolHive to securely handle authentication for clients. Stay tuned for updates on this feature.
:::
:::note Obtaining JWT tokens
How to obtain JWT tokens varies by identity provider and is outside the scope of this guide. Consult your identity provider's documentation for specific instructions on:
- Interactive user authentication flows (OAuth 2.0 Authorization Code flow)
- Service-to-service authentication (Client Credentials flow)
- API token generation and management
For Kubernetes service accounts, tokens are automatically mounted at
/var/run/secrets/kubernetes.io/serviceaccount/token
in pods.
:::
To verify that authentication is working, you can use a tool like curl
to make
a request to your MCP server:
curl -H "Authorization: Bearer <your-jwt-token>" \
<toolhive-server-url>
Set up authorization
ToolHive uses Amazon's Cedar policy language for fine-grained, secure-by-default authorization. Authorization is explicit: if a request is not explicitly permitted by a policy, it is denied. Deny rules always take precedence over permit rules.
Step 1: Create an authorization configuration file
Create a JSON or YAML file with Cedar policies. Here's an example in JSON format:
{
"version": "1.0",
"type": "cedarv1",
"cedar": {
"policies": [
// Allow everyone to use the weather tool
"permit(principal, action == Action::\"call_tool\", resource == Tool::\"weather\");",
// Restrict admin_tool to a specific user
"permit(principal == Client::\"alice123\", action == Action::\"call_tool\", resource == Tool::\"admin_tool\");",
// Role-based access: only users with the 'premium' role can call any tool
"permit(principal, action == Action::\"call_tool\", resource) when { principal.claim_roles.contains(\"premium\") };",
// Attribute-based: allow calculator tool only for add/subtract operations
"permit(principal, action == Action::\"call_tool\", resource == Tool::\"calculator\") when { resource.arg_operation == \"add\" || resource.arg_operation == \"subtract\" };"
],
"entities_json": "[]"
}
}
You can also define custom resource attributes in entities_json
for per-tool
ownership or sensitivity labels.
For more policy examples and advanced usage, see Cedar policies.
Save this file to a location accessible to ToolHive, such as
/path/to/authz-config.json
.
Step 2: Run an MCP server with authorization
Start your MCP server with the authorization configuration:
thv run \
--authz-config /path/to/authz-config.json \
<server-name>
You can combine this with the authentication parameters from the previous section:
thv run \
--oidc-audience <your-audience> \
--oidc-client-id <your-client-id> \
--oidc-issuer <https://your-oidc-issuer.com> \
--oidc-jwks-url <https://your-oidc-issuer.com/path/to/jwks> \
--authz-config /path/to/authz-config.json \
<server-name>
Step 3: Test authorization
Once your server is running with authorization enabled, clients will be subject to the Cedar policies defined in your configuration file. When a client attempts to perform an action, ToolHive will evaluate the request against the policies. If the request is permitted, the action will proceed; otherwise, it will be denied with a 403 Forbidden response.
Troubleshooting
Authentication issues
If clients can't authenticate:
-
Check that the JWT token is valid and not expired
-
Verify that the audience and issuer match your configuration
-
Ensure the JWKS URL is accessible
-
Check the server logs for specific authentication errors:
thv logs <server-name>
Authorization issues
If authenticated clients are denied access:
- Make sure your Cedar policies explicitly permit the specific action (remember, default deny)
- Check that the principal, action, and resource match what's in your policies (including case and formatting)
- Examine any conditions in your policies to ensure they're satisfied (for example, required JWT claims or tool arguments)
- Remember that Cedar uses a default deny policy—if no policy explicitly permits an action, it will be denied
Troubleshooting tip: If access is denied, check that your policies explicitly permit the action. Cedar uses a default deny model—if no policy matches, the request is denied.
CLI-specific issues
If you're having issues with the CLI:
- Verify that the configuration file path is correct and accessible
- Check that the server name matches an available MCP server
- Ensure all required CLI flags are provided
Related information
- For conceptual understanding, see Authentication and authorization framework
- For detailed Cedar policy syntax, see Cedar policies and the Cedar documentation