Securing GraphQL API Access with Token Exchange via ToolHive and Okta
These articles are AI-generated summaries. Please check the original sources for full details.
Using Token Exchange with ToolHive and Okta for MCP Server to GraphQL Authentication
This article explains how to implement secure authentication for a GraphQL API using Okta and ToolHive, leveraging token exchange to ensure that only authorized users can access backend services through an MCP server. The setup ensures role-based access, clean audit trails, and separation of concerns between the MCP server and backend API.
Key Concepts and Setup
Environment Requirements
- Backend API: Requires tokens with
aud=backendandscopes=[backend-api:read]. - MCP Server: Requires tokens with
aud=mcpserverandscopes=mcp:tools:call. - Authentication Flow: Users authenticate via VSCode, which connects to the MCP server (ToolHive), which exchanges tokens for backend API access.
Okta Configuration
- Authorization Servers: Two servers are created:
- MCP Server AS: Issues tokens for
mcp:tools:call. - Backend AS: Issues tokens for
backend-api:read.
- MCP Server AS: Issues tokens for
- Trust Between Servers: The backend AS must trust the MCP server AS for token exchange.
Application Setup
- VSCode Client: OIDC application with Redirect URIs
http://127.0.0.1:33418andhttps://vscode.dev/redirect. - ToolHive Client: API Services application with Token Exchange grant enabled. Requires unchecking “Require Demonstrating Proof of Possession” and assigning token exchange policies.
Policies
- MCP Client Policy: Grants
mcp:tools:callscope to the VSCode client on the MCP server AS. - Token Exchange Policy: Allows the ToolHive client to exchange tokens for
backend-api:readscope on the backend AS.
Implementation Steps
Cloning and Configuring the GraphQL Server
-
Clone the Apollo GraphQL demo repository:
git clone https://github.com/StacklokLabs/apollo-mcp-auth-demo -
Configure
.envwith Okta domain, issuer, audience, and scopes:OKTA_DOMAIN=integrator-3683736.okta.com OKTA_ISSUER=https://integrator-3683736.okta.com/oauth2/auswdh3wurjeJ62La697 OKTA_AUDIENCE=backend REQUIRED_SCOPES=backend-api:read -
Start the server:
npm install npm start
Configuring the MCP Server (ToolHive)
-
Modify
apollo-mcp-config.yamlto specify the backend AS:transport: type: sse port: 8000 auth: servers: - https://integrator-3683736.okta.com/oauth2/auswdh3wurjeJ62La697 -
Run ToolHive with token exchange parameters:
thv run \ --oidc-audience mcpserver \ --token-exchange-audience backend \ --token-exchange-client-id 0oawdgw7krVBSwzIx697 \ --token-exchange-client-secret O2zqVb-evhKgfBOD-PRVDs5HFyCXAnRZAwxAtQOH9oGt72aBrLBiwEVlyyTengj9 \ --token-exchange-url https://integrator-3683736.okta.com/oauth2/auswdh3wurjeJ62La697/v1/token \ apollo-mcp-server -- /config.yaml
Authentication Flow and Token Exchange
VSCode Integration
- VSCode connects to the MCP server via ToolHive.
- The user authenticates with Okta, receiving a token with
aud=mcpserver. - ToolHive exchanges this token for a backend API token (
aud=backend) using the configured policies.
Token Exchange Process
- Client Token:
{ "iss": "https://idp.example.com/oauth2/default", "aud": "mcpserver", "scp": ["mcp:tools:call"], "sub": "[email protected]" } - Exchanged Token:
{ "iss": "https://idp.example.com/oauth2/default", "aud": "backend", "scp": ["backend-api:read"], "sub": "[email protected]" }
Benefits and Best Practices
Security and Efficiency
- Role-Based Access: Tokens ensure only authorized users can access specific services.
- Audit Trails: Each API call is attributed to a user, not a generic service account.
- Short-Lived Tokens: Reduces the risk of token misuse compared to long-lived secrets.
Recommendations
- Avoid Hardcoding Secrets: Use environment variables or files for
--token-exchange-client-secret. - Validate Redirect URIs: Ensure VSCode’s Redirect URIs match Okta’s configuration.
- Test in Isolated Environments: Use separate Okta realms for development and production.
Working Example
# Start the GraphQL server
npm start
# Run ToolHive with token exchange
thv run \
--oidc-audience mcpserver \
--token-exchange-audience backend \
--token-exchange-client-id 0oawdgw7krVBSwzIx697 \
--token-exchange-client-secret <SECRET> \
--token-exchange-url https://integrator-3683736.okta.com/oauth2/auswdh3wurjeJ62La697/v1/token \
apollo-mcp-server -- /config.yaml
References
https://dev.to/stacklok/using-token-exchange-with-toolhive-and-okta-for-mcp-server-to-graphql-authentication-3ehi Continue reading
Next article
Video Invisible Watermarking at Scale: Meta's Approach to Content Provenance
Related Content
Scaling Laravel Queues: A Practical Guide to AWS SQS
A comprehensive guide to transitioning Laravel applications from default queue systems to AWS SQS for high availability, scalability, and reliability in handling thousands of jobs per hour.
Reverse-Engineering a Dockerfile from an Existing Docker Image
A step-by-step guide to reconstructing a Dockerfile from an existing Docker image using the `docker history` command and layer analysis.
Understanding and Creating Resource Groups in Microsoft Azure
A guide to creating and understanding Resource Groups in Microsoft Azure for cloud resource management and governance.