Proxy with authentication
This guide explains how to use the thv proxy
command to create a standalone
transparent HTTP proxy with authentication support for MCP servers. The proxy
provides flexible authentication options for both incoming requests to the proxy
and outgoing requests to remote MCP servers.
Overview
The thv proxy
command creates a standalone HTTP proxy that forwards requests
to an MCP server endpoint. Unlike thv run
, which creates a managed workload,
thv proxy
runs as a standalone process without container management.
Key capabilities:
- Transparent request forwarding to any MCP server endpoint
- OAuth/OIDC authentication to remote MCP servers
- Automatic authentication detection via WWW-Authenticate headers
- OIDC-based access control for incoming proxy requests
- Dynamic client registration (RFC 7591) for automatic OAuth client setup
- Secure credential handling via files or environment variables
Authentication modes
The proxy supports four authentication scenarios:
- No authentication: Simple transparent forwarding
- Outgoing authentication: Authenticate to remote MCP servers using OAuth/OIDC
- Incoming authentication: Protect the proxy endpoint with OIDC validation
- Bidirectional: Both incoming and outgoing authentication
Basic proxy setup
Simple transparent proxy
Create a basic proxy without authentication:
thv proxy my-server --target-uri http://localhost:8080
This creates a proxy that forwards all requests to http://localhost:8080
without any authentication.
Specify proxy host and port
By default, the proxy listens on 127.0.0.1
with a random port. To specify
custom values:
thv proxy my-server \
--target-uri http://localhost:8080 \
--host 0.0.0.0 \
--port 8000
Outgoing authentication to remote servers
The proxy can authenticate to remote MCP servers that require OAuth or OIDC authentication. This is useful when you need to access protected remote services.
OIDC authentication
For OpenID Connect-compliant servers, provide the issuer URL and client credentials:
thv proxy my-server \
--target-uri https://api.example.com \
--remote-auth \
--remote-auth-issuer https://auth.example.com \
--remote-auth-client-id my-client-id \
--remote-auth-client-secret-file /path/to/secret
Always use --remote-auth-client-secret-file
instead of
--remote-auth-client-secret
in production environments. The file-based
approach prevents credentials from appearing in process lists or command
history.
OAuth2 authentication
For non-OIDC OAuth2 servers, specify the authorization and token endpoints explicitly:
thv proxy my-server \
--target-uri https://api.example.com \
--remote-auth \
--remote-auth-authorize-url https://auth.example.com/oauth/authorize \
--remote-auth-token-url https://auth.example.com/oauth/token \
--remote-auth-client-id my-client-id \
--remote-auth-client-secret-file /path/to/secret
Auto-detect authentication
The proxy can automatically detect if a remote server requires authentication by examining WWW-Authenticate headers:
thv proxy my-server \
--target-uri https://protected-api.com \
--remote-auth-client-id my-client-id
When authentication is detected, the proxy automatically initiates the appropriate OAuth flow.
Dynamic client registration
When no client credentials are provided, the proxy can automatically register an OAuth client using RFC 7591 dynamic client registration:
thv proxy my-server \
--target-uri https://protected-api.com \
--remote-auth \
--remote-auth-issuer https://auth.example.com
This feature:
- Eliminates the need to pre-configure OAuth clients
- Automatically discovers the registration endpoint via OIDC
- Supports PKCE flow for enhanced security
Dynamic client registration requires the remote authorization server to support RFC 7591. Not all OAuth providers support this feature.
Incoming authentication (proxy protection)
You can protect the proxy endpoint itself with OIDC validation, requiring clients to provide valid JWT tokens when connecting to the proxy.
OIDC validation for incoming requests
thv proxy my-server \
--target-uri http://localhost:8080 \
--oidc-issuer https://auth.example.com \
--oidc-audience my-audience \
--oidc-client-id my-client-id
This configuration:
- Requires clients to include a valid JWT in the
Authorization
header - Validates the token signature, expiration, and claims
- Extracts identity information for authorization decisions
Token introspection
For advanced scenarios, you can use token introspection:
thv proxy my-server \
--target-uri http://localhost:8080 \
--oidc-issuer https://auth.example.com \
--oidc-audience my-audience \
--oidc-client-id my-client-id \
--oidc-client-secret my-client-secret \
--oidc-introspection-url https://auth.example.com/oauth/introspect
Bidirectional authentication
Combine incoming and outgoing authentication for end-to-end security:
thv proxy my-server \
--target-uri https://api.example.com \
--remote-auth \
--remote-auth-issuer https://remote-auth.example.com \
--remote-auth-client-id remote-client-id \
--remote-auth-client-secret-file /path/to/remote-secret \
--oidc-issuer https://local-auth.example.com \
--oidc-audience my-audience \
--oidc-client-id local-client-id
This setup:
- Validates incoming requests from clients using OIDC
- Authenticates outgoing requests to the remote server using OAuth/OIDC
- Provides complete authentication chain from client to remote server
Advanced configuration
Custom OAuth scopes
Specify the OAuth scopes required by the remote server:
thv proxy my-server \
--target-uri https://api.example.com \
--remote-auth \
--remote-auth-issuer https://auth.example.com \
--remote-auth-client-id my-client-id \
--remote-auth-client-secret-file /path/to/secret \
--remote-auth-scopes openid,profile,email,custom-scope
If --remote-auth-scopes
is not specified, OIDC authentication defaults to
openid,profile,email
.
Authentication timeout
Adjust the timeout for slow networks or interactive authentication flows:
thv proxy my-server \
--target-uri https://api.example.com \
--remote-auth \
--remote-auth-issuer https://auth.example.com \
--remote-auth-client-id my-client-id \
--remote-auth-client-secret-file /path/to/secret \
--remote-auth-timeout 2m
Headless authentication
For non-interactive environments (CI/CD, servers), skip browser-based OAuth flows:
thv proxy my-server \
--target-uri https://api.example.com \
--remote-auth \
--remote-auth-issuer https://auth.example.com \
--remote-auth-client-id my-client-id \
--remote-auth-client-secret-file /path/to/secret \
--remote-auth-skip-browser
This requires client credentials flow or pre-authorized tokens.
Custom OAuth callback port
The proxy uses a temporary HTTP server for OAuth callbacks during authentication. To specify a custom callback port:
thv proxy my-server \
--target-uri https://api.example.com \
--remote-auth \
--remote-auth-issuer https://auth.example.com \
--remote-auth-client-id my-client-id \
--remote-auth-client-secret-file /path/to/secret \
--remote-auth-callback-port 9000
The default callback port is 8666
.
Resource URL for OAuth discovery
For servers using RFC 9728 OAuth 2.0 Authorization Server Metadata for Resource Indicators, specify the resource URL:
thv proxy my-server \
--target-uri https://api.example.com \
--remote-auth \
--remote-auth-issuer https://auth.example.com \
--remote-auth-client-id my-client-id \
--remote-auth-client-secret-file /path/to/secret \
--resource-url https://resource.example.com
Credential management
Client secret sources
OAuth client secrets can be provided via three methods (in order of precedence):
--remote-auth-client-secret
flag (not recommended for production)--remote-auth-client-secret-file
flag (recommended)TOOLHIVE_REMOTE_OAUTH_CLIENT_SECRET
environment variable
Using environment variables
export TOOLHIVE_REMOTE_OAUTH_CLIENT_SECRET="your-secret-here"
thv proxy my-server \
--target-uri https://api.example.com \
--remote-auth \
--remote-auth-issuer https://auth.example.com \
--remote-auth-client-id my-client-id
Using secret files
echo "your-secret-here" > /secure/path/secret.txt
chmod 600 /secure/path/secret.txt
thv proxy my-server \
--target-uri https://api.example.com \
--remote-auth \
--remote-auth-issuer https://auth.example.com \
--remote-auth-client-id my-client-id \
--remote-auth-client-secret-file /secure/path/secret.txt
Common use cases
Protecting a local MCP server
Run a local MCP server and protect it with OIDC authentication:
# Start your MCP server on localhost:8080
# Then create a protected proxy
thv proxy protected-mcp \
--target-uri http://localhost:8080 \
--port 3000 \
--oidc-issuer https://auth.example.com \
--oidc-audience mcp-users \
--oidc-client-id mcp-proxy
Clients now connect to http://localhost:3000
with valid JWT tokens.
Accessing a protected remote MCP server
Connect to a remote MCP server that requires OAuth authentication:
thv proxy remote-mcp \
--target-uri https://api.example.com/mcp \
--port 3000 \
--remote-auth \
--remote-auth-issuer https://auth.example.com \
--remote-auth-client-id your-client-id \
--remote-auth-client-secret-file /path/to/secret
Clients connect to http://localhost:3000
without handling OAuth flows.
Creating a secure gateway
Set up a secure gateway with authentication on both sides:
thv proxy secure-gateway \
--target-uri https://api.example.com/mcp \
--port 3000 \
--remote-auth \
--remote-auth-issuer https://remote.example.com \
--remote-auth-client-id remote-id \
--remote-auth-client-secret-file /path/to/remote-secret \
--oidc-issuer https://local.example.com \
--oidc-audience gateway-users \
--oidc-client-id gateway-proxy
Troubleshooting
Authentication flow fails
If OAuth/OIDC authentication fails:
-
Verify the issuer URL is correct and accessible
-
Check that client ID and secret are valid
-
Ensure the redirect URI is properly configured in your OAuth provider
-
Check the callback port is not blocked by firewalls
-
Use
--debug
flag for detailed logs:thv proxy my-server --debug \
--target-uri https://api.example.com \
--remote-auth \
--remote-auth-issuer https://auth.example.com \
--remote-auth-client-id my-client-id \
--remote-auth-client-secret-file /path/to/secret
Dynamic client registration fails
If automatic client registration doesn't work:
- Verify the authorization server supports RFC 7591
- Check that the OIDC discovery endpoint is accessible
- Ensure the issuer URL includes
/.well-known/openid-configuration
- Try with explicit client credentials instead
Token validation fails
If incoming token validation fails:
- Verify the JWT is properly formatted
- Check that the
Authorization
header usesBearer
scheme - Ensure the token hasn't expired
- Verify the audience and issuer match your configuration
- Check JWKS URL is accessible for signature verification