JWT Token Vending Service for MCP Gateway¶
The JWT Token Vending Service provides a user-friendly mechanism for generating personal access tokens without the use of an external IdP that can be used for programmatic access to MCP servers. This service bridges the gap between human authentication (web UI sessions) and machine authentication (JWT tokens), enabling users to create tokens with scoped permissions for automation, scripting, and agent access.
The Challenge with Token Management in Enterprise MCP Deployments¶
In enterprise scenarios, users often need to provide programmatic access to MCP servers for various automation tasks, CI/CD pipelines, and AI agents. Traditional approaches present several challenges:
- Manual Token Management: Requiring users to manually generate M2M credentials through AWS Cognito or other IdPs creates friction and security risks
- Scope Complexity: Users need to understand complex scope configurations and may accidentally grant excessive permissions
- Token Lifecycle: No centralized way to manage token expiration, renewal, or revocation
- Audit Trail: Difficulty tracking which tokens were generated by whom and for what purpose
A Solution with Integrated Token Vending¶
The JWT Token Vending Service provides an enterprise-ready solution that integrates directly with the existing MCP Gateway authentication infrastructure, allowing users to generate scoped JWT tokens through a familiar web interface.
Here is an architecture diagram showing how the token vending service integrates with the existing system:
graph TB
%% Users and Token Generation Flow
subgraph UserFlow["User Token Generation Flow"]
direction TB
User[User<br/>Web UI Session]
TokenUI[Token Generation<br/>Web Interface]
User -->|Authenticated Session| TokenUI
end
%% Core Infrastructure
subgraph Infrastructure["MCP Gateway & Registry Infrastructure"]
direction TB
Nginx["Nginx<br/>Reverse Proxy"]
AuthServer["Auth Server<br/>(Enhanced with Token Vending)"]
Registry["Registry<br/>Web UI + Token Generation"]
RegistryMCP["Registry<br/>MCP Server"]
end
%% Generated Token Usage
subgraph TokenUsage["Token Usage"]
direction TB
Agent[AI Agent<br/>with Generated Token]
Script[Automation Script<br/>with Generated Token]
Pipeline[CI/CD Pipeline<br/>with Generated Token]
end
%% Identity Provider
IdP[Identity Provider<br/>Amazon Cognito]
%% MCP Server Farm
subgraph MCPFarm["MCP Server Farm"]
direction TB
MCP1[MCP Server 1<br/>CurrentTime]
MCP2[MCP Server 2<br/>FinInfo]
MCP3[MCP Server 3<br/>Custom]
MCPn[MCP Server n<br/>...]
end
%% Token Generation Flow
TokenUI -->|POST /api/tokens/generate<br/>with user context| Registry
Registry -->|POST /internal/tokens<br/>with user scopes| AuthServer
AuthServer -->|Self-signed JWT<br/>with HMAC-SHA256| Registry
Registry -->|Display token<br/>to user| TokenUI
%% Token Usage Flow
Agent -->|MCP requests<br/>with Bearer token| Nginx
Script -->|API calls<br/>with Bearer token| Nginx
Pipeline -->|Automated access<br/>with Bearer token| Nginx
%% Internal routing and validation
Nginx -->|Route /mcpgw/*<br/>Auth validation| AuthServer
Nginx -->|Route /mcpgw/*<br/>Tool discovery| RegistryMCP
Nginx -->|Route /tokens<br/>Token UI| Registry
Nginx -->|Route /server1/*<br/>Proxy to MCP servers| MCP1
Nginx -->|Route /server2/*<br/>Proxy to MCP servers| MCP2
Nginx -->|Route /serverN/*<br/>Proxy to MCP servers| MCP3
Nginx -->|Route /serverN/*<br/>Proxy to MCP servers| MCPn
%% Auth flows
IdP -.->|User session validation<br/>Group/scope mapping| AuthServer
AuthServer -.->|Self-signed JWT validation<br/>Scope enforcement| AuthServer
%% Styling
classDef userStyle fill:#e8f5e8,stroke:#2e7d32,stroke-width:2px
classDef tokenStyle fill:#fff3e0,stroke:#e65100,stroke-width:2px
classDef agentStyle fill:#e1f5fe,stroke:#01579b,stroke-width:2px
classDef idpStyle fill:#fff3e0,stroke:#e65100,stroke-width:2px
classDef nginxStyle fill:#f3e5f5,stroke:#4a148c,stroke-width:2px
classDef authStyle fill:#ffebee,stroke:#c62828,stroke-width:2px
classDef registryStyle fill:#fff8e1,stroke:#f57f17,stroke-width:2px
classDef mcpStyle fill:#e3f2fd,stroke:#1976d2,stroke-width:2px
class UserFlow userStyle
class User userStyle
class TokenUI tokenStyle
class TokenUsage agentStyle
class Agent,Script,Pipeline agentStyle
class IdP idpStyle
class Nginx nginxStyle
class AuthServer authStyle
class Registry,RegistryMCP registryStyle
class MCP1,MCP2,MCP3,MCPn mcpStyle
Architecture Components for Token Vending¶
The JWT Token Vending Service extends the existing MCP Gateway infrastructure with new capabilities:
Enhanced Registry Web UI¶
- Token Generation Interface: User-friendly form for creating JWT tokens with custom scopes and expiration
- Scope Validation: Real-time validation ensuring requested scopes are subset of user's current permissions
- Token Display: Secure, one-time display of generated tokens with copy functionality and usage instructions
Enhanced Auth Server¶
- Internal Token Endpoint: New
/internal/tokens
endpoint for generating self-signed JWT tokens - Scope Validation Logic: Ensures generated tokens cannot exceed user's current permissions
- Rate Limiting: Prevents token generation abuse with configurable limits per user
- Self-Signed JWT Support: Validates both Cognito tokens and internally generated tokens
Token Security Features¶
- HMAC-SHA256 Signing: Uses shared secret key for token signing and validation
- Scope Inheritance: Generated tokens can have same or fewer permissions than user's current scopes
- Configurable Expiration: Token lifetime from 1-24 hours with 8-hour default
- Unique Token IDs: Each token has a unique identifier for potential tracking and revocation
At a high-level the token generation and usage flow works as follows:
sequenceDiagram
participant User
participant Browser
participant Registry as Registry<br/>Web UI
participant AuthServer as Auth Server
participant Agent
participant Gateway as Gateway<br/>(Nginx)
participant MCP as MCP Server
%% Token Generation Flow
Note over User,AuthServer: Token Generation Flow
User->>Browser: Navigate to /tokens
Browser->>Registry: GET /tokens with session cookie
Registry->>Registry: Validate user session + extract scopes
Registry->>Browser: Token generation form
User->>Browser: Configure token (scopes, expiration, description)
Browser->>Registry: POST /api/tokens/generate
Registry->>Registry: Validate requested scopes ⊆ user scopes
Registry->>AuthServer: POST /internal/tokens with user context
AuthServer->>AuthServer: Rate limit check (10/hour/user)
AuthServer->>AuthServer: Generate JWT with HMAC-SHA256
AuthServer->>Registry: Return signed JWT token
Registry->>Browser: Display token with copy functionality
Browser->>User: Show token + usage instructions
%% Token Usage Flow
Note over Agent,MCP: Token Usage Flow
User->>Agent: Provide generated JWT token
Agent->>Gateway: MCP request with Bearer token
Gateway->>AuthServer: Validate token + extract scopes
alt Self-Signed Token
AuthServer->>AuthServer: Detect issuer: "mcp-auth-server"
AuthServer->>AuthServer: Validate HMAC-SHA256 signature
AuthServer->>AuthServer: Extract scopes + enforce access
else Cognito Token (Fallback)
AuthServer->>AuthServer: Standard Cognito validation
end
alt Sufficient Permissions
AuthServer->>Gateway: 200 OK + allowed scopes
Gateway->>MCP: Forward MCP request
MCP->>Gateway: MCP response
Gateway->>Agent: MCP response
else Insufficient Permissions
AuthServer->>Gateway: 403 Access Denied
Gateway->>Agent: 403 Access Denied
end
-
A User authenticates to the Registry web UI using their existing session (derived from Cognito OAuth or M2M flow) which contains their current scopes and permissions.
-
The User navigates to the token generation interface at
/tokens
and configures their desired token parameters including optional custom scopes (must be subset of current scopes), expiration time (1-24 hours), and description. -
The Registry validates the user's session, ensures requested scopes are a subset of the user's current permissions, and calls the Auth Server's internal token generation endpoint with the user context and token parameters.
-
The Auth Server performs security checks (rate limiting, scope validation, expiration limits) and generates a self-signed JWT token using HMAC-SHA256 with the shared secret key. The token contains standard JWT claims plus MCP-specific metadata.
-
The Registry displays the generated token to the user with copy functionality, usage instructions, and security warnings. The token is shown only once for security.
-
The User saves the token securely and provides it to their Agent or automation script for programmatic access to MCP servers.
-
When the Agent makes MCP requests, it includes the generated JWT token in the Authorization header. The Gateway forwards the request to the Auth Server for validation.
-
The Auth Server detects self-signed tokens by the issuer claim, validates the HMAC-SHA256 signature using the shared secret, and enforces scope-based access control using the same logic as Cognito tokens.
-
If the token is valid and the requested operation is within the token's scope, the Gateway forwards the request to the appropriate MCP Server. Otherwise, it returns a 403 Access Denied response.
The above implementation provides a seamless way for users to generate programmatic access tokens without requiring direct interaction with the Identity Provider, while maintaining the same security guarantees and scope enforcement as the existing authentication system.
Agent Integration¶
The JWT Token Vending Service integrates seamlessly with existing agent authentication patterns through enhanced command-line support:
Enhanced Agent Command Line Interface¶
The agent now supports direct JWT token usage through a new --jwt-token
parameter:
# Method 1: Direct token usage
python agent.py \
--jwt-token "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..." \
--message "What is the current time in New York?"
# Method 2: Environment variable
export JWT_TOKEN="eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
python agent.py --jwt-token "$JWT_TOKEN" --message "List available servers"
# Method 3: Token from file
echo "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..." > ~/.mcp/jwt_token
python agent.py --jwt-token "$(cat ~/.mcp/jwt_token)" --message "Help me analyze data"
Token Storage Best Practices¶
Secure Storage Options¶
# Option 1: Encrypted environment file
echo "JWT_TOKEN=your_token_here" | gpg --encrypt > ~/.mcp/token.gpg
# Option 2: System keyring (macOS)
security add-generic-password -a "$USER" -s "mcp-jwt-token" -w "your_token_here"
# Option 3: Secure file with restricted permissions
echo "your_token_here" > ~/.mcp/jwt_token
chmod 600 ~/.mcp/jwt_token
CI/CD Integration¶
# GitHub Actions example
name: MCP Agent Workflow
on: [push]
jobs:
run-agent:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Run MCP Agent
env:
JWT_TOKEN: ${{ secrets.MCP_JWT_TOKEN }}
run: |
python agent.py --jwt-token "$JWT_TOKEN" --message "Deploy analysis"
Security Features and Considerations¶
Token Security Implementation¶
Rate Limiting¶
- Per-User Limits: Maximum 10 tokens per user per hour
- Sliding Window: Uses hourly time slots for rate calculation
- Memory-Based: Simple in-memory counter with automatic cleanup
- Configurable: Limits adjustable via environment variables
Scope Inheritance and Validation¶
- Subset Validation: Generated tokens cannot exceed user's current permissions
- Real-Time Validation: Scope checks performed at generation time
- Default Behavior: Empty scope request defaults to user's full scope set
- JSON Validation: Custom scope uploads validated for proper JSON format
Token Lifecycle Management¶
- Configurable Expiration: 1-24 hour range with 8-hour default
- No Refresh: Tokens cannot be refreshed, must be regenerated
- Unique Identifiers: Each token has a unique
jti
claim for tracking - Self-Contained: All authorization data embedded in token
Cryptographic Implementation¶
HMAC-SHA256 Signing¶
# Token generation process
payload = {
"iss": "mcp-auth-server",
"aud": "mcp-registry",
"sub": username,
"scope": " ".join(requested_scopes),
"exp": current_time + (expires_in_hours * 3600),
"iat": current_time,
"jti": str(uuid.uuid4()),
"token_use": "access",
"client_id": "user-generated",
"token_type": "user_generated"
}
# Sign with shared secret
access_token = jwt.encode(payload, SECRET_KEY, algorithm='HS256')
Token Validation Process¶
# Validation with issuer detection
try:
# Quick check for self-signed tokens
unverified_claims = jwt.decode(token, options={"verify_signature": False})
if unverified_claims.get('iss') == 'mcp-auth-server':
# Validate self-signed token
claims = jwt.decode(token, SECRET_KEY, algorithms=['HS256'],
issuer='mcp-auth-server', audience='mcp-registry')
scopes = claims.get('scope', '').split()
return {'valid': True, 'scopes': scopes, 'method': 'self_signed'}
else:
# Fall back to Cognito validation
return validate_cognito_token(token)
except jwt.InvalidTokenError:
return {'valid': False, 'error': 'Invalid token'}
Security Best Practices¶
For Users¶
- Minimal Scopes: Generate tokens with only required permissions
- Short Expiration: Use shortest practical token lifetime
- Secure Storage: Store tokens in encrypted or protected locations
- Regular Rotation: Regenerate tokens periodically
- Monitor Usage: Track token usage in application logs
For Administrators¶
- Audit Logging: Monitor token generation patterns and frequency
- Scope Configuration: Regularly review and update scope definitions
- Rate Limit Tuning: Adjust rate limits based on usage patterns
- Key Management: Protect the shared SECRET_KEY used for signing
- Access Reviews: Periodically review user permissions and group memberships
Threat Model and Mitigations¶
Token Theft¶
- Risk: Stolen tokens provide unauthorized access
- Mitigation: Short expiration times, scope limitations, audit logging
Scope Escalation¶
- Risk: Users attempt to generate tokens with excessive permissions
- Mitigation: Strict subset validation, real-time scope checking
Rate Limit Bypass¶
- Risk: Automated token generation for abuse
- Mitigation: Per-user rate limiting, monitoring, account lockout policies
Replay Attacks¶
- Risk: Intercepted tokens used maliciously
- Mitigation: HTTPS enforcement, short token lifetimes, unique token IDs
Implementation Configuration¶
Environment Variables¶
# Token generation settings
MAX_TOKEN_LIFETIME_HOURS=24 # Maximum token lifetime
DEFAULT_TOKEN_LIFETIME_HOURS=8 # Default token lifetime
MAX_TOKENS_PER_USER_PER_HOUR=10 # Rate limiting
# JWT settings
JWT_ISSUER="mcp-auth-server" # Token issuer
JWT_AUDIENCE="mcp-registry" # Token audience
SECRET_KEY="your-shared-secret" # HMAC signing key (must be shared)
Scope Configuration¶
Generated tokens inherit scope validation from the existing scopes.yml
configuration:
# Example scope allowing read access to time servers
mcp-servers-time/read:
- server: "currenttime"
methods: ["initialize", "tools/list", "tools/call"]
tools: ["current_time_by_timezone", "current_time_utc"]
# Example scope for financial data access
mcp-servers-finance/read:
- server: "fininfo"
methods: ["initialize", "tools/list", "tools/call"]
tools: ["get_stock_price", "get_market_data"]
# Admin scope with full access
mcp-registry-admin:
- server: "*"
methods: ["*"]
tools: ["*"]
User Interface Configuration¶
The token generation interface provides:
Token Configuration Options¶
- Description: Optional human-readable token description
- Expiration: Dropdown with 1, 8, and 24-hour options
- Scope Method: Radio buttons for "Use current scopes" or "Custom JSON"
- Custom Scopes: JSON textarea for advanced users
User Experience Features¶
- Current Permissions Display: Shows user's active scopes as badges
- Real-time Validation: Client-side validation of JSON scope format
- Copy Functionality: Multiple copy methods with fallbacks for different browsers
- Usage Instructions: Clear examples of how to use the generated token
- Security Warnings: Prominent warnings about token storage and sharing
By implementing the JWT Token Vending Service, organizations can provide their users with a secure, user-friendly way to generate programmatic access tokens while maintaining enterprise-grade security controls and comprehensive audit capabilities. The service seamlessly integrates with existing MCP Gateway infrastructure and provides a foundation for advanced token management features.