kafka-mcp-server

OAuth 2.1 Authentication for Kafka MCP Server

Overview

Kafka MCP Server supports OAuth 2.1 authentication when running in HTTP transport mode. This enables secure, token-based authentication for MCP clients accessing the server over HTTP.

The implementation uses oauth-mcp-proxy@v1.0.0, a standalone OAuth 2.1 library designed specifically for Go MCP servers.

Features

Architecture

OAuth Flow

┌─────────────────┐
│   MCP Client    │
│ (Cursor, etc)   │
└────────┬────────┘
         │
         │ Bearer Token
         │ Authorization: Bearer <token>
         ▼
┌─────────────────────────────────┐
│   HTTP Server                   │
│                                 │
│  ┌──────────────────────────┐  │
│  │   OAuth Middleware       │  │
│  │  - Token Extraction      │  │
│  │  - Token Validation      │  │
│  │  - User Context Inject   │  │
│  └──────────┬───────────────┘  │
│             ▼                   │
│  ┌──────────────────────────┐  │
│  │   MCP Server Handler     │  │
│  │   /mcp endpoint          │  │
│  └──────────────────────────┘  │
└─────────────────────────────────┘
         │
         ▼
┌─────────────────┐
│  Kafka Cluster  │
└─────────────────┘

Implementation Architecture

The OAuth integration follows a specific initialization sequence:

  1. Mux Creation: http.NewServeMux() created in main()
  2. OAuth Registration: CreateOAuthOption(cfg, mux) registers OAuth routes on mux
  3. Server Creation: NewMCPServer(name, version, oauthOption) with OAuth middleware
  4. HTTP Server: startHTTPServer() mounts MCP handler and starts server

This ensures OAuth routes and middleware are properly configured before the server starts handling requests.

OAuth Modes

Native Mode (Client-Managed)

Best for: Environments where clients can handle OAuth flows directly.

Characteristics:

Configuration:

export MCP_TRANSPORT=http
export MCP_HTTP_PORT=8080
export OAUTH_ENABLED=true
export OAUTH_MODE=native
export OAUTH_PROVIDER=okta
export OAUTH_SERVER_URL=http://localhost:8080
export OIDC_ISSUER=https://company.okta.com
export OIDC_AUDIENCE=api://kafka-mcp-server

Proxy Mode (Server-Managed)

Best for: Centralized OAuth management, simple clients.

Characteristics:

Configuration:

export MCP_TRANSPORT=http
export MCP_HTTP_PORT=8080
export OAUTH_ENABLED=true
export OAUTH_MODE=proxy
export OAUTH_PROVIDER=google
export OAUTH_SERVER_URL=http://localhost:8080
export OIDC_ISSUER=https://accounts.google.com
export OIDC_CLIENT_ID=your-client-id.apps.googleusercontent.com
export OIDC_CLIENT_SECRET=your-client-secret
export OIDC_AUDIENCE=your-client-id.apps.googleusercontent.com
export OAUTH_REDIRECT_URIS=http://localhost:8080/oauth/callback
export JWT_SECRET=$(openssl rand -hex 32)

Supported Providers

1. HMAC (Development/Testing)

Simple symmetric key authentication for local development.

export OAUTH_PROVIDER=hmac
export OAUTH_MODE=native
export JWT_SECRET=$(openssl rand -hex 32)
export OIDC_ISSUER=http://localhost:8080
export OIDC_AUDIENCE=api://kafka-mcp-server

Use case: Local testing without external OAuth provider.

2. Okta

Enterprise SSO provider.

Setup Requirements:

Native Mode:

export OAUTH_PROVIDER=okta
export OAUTH_MODE=native
export OIDC_ISSUER=https://company.okta.com
export OIDC_AUDIENCE=api://kafka-mcp-server

Proxy Mode: Add client credentials

export OIDC_CLIENT_ID=your-okta-client-id
export OIDC_CLIENT_SECRET=your-okta-client-secret
export OAUTH_REDIRECT_URIS=http://localhost:8080/oauth/callback
export JWT_SECRET=$(openssl rand -hex 32)

3. Google

Google Workspace authentication.

Setup Requirements:

Configuration:

export OAUTH_PROVIDER=google
export OIDC_ISSUER=https://accounts.google.com
export OIDC_AUDIENCE=your-client-id.apps.googleusercontent.com

4. Azure AD (azure)

Microsoft identity platform.

Setup Requirements:

Configuration:

export OAUTH_PROVIDER=azure
export OIDC_ISSUER=https://login.microsoftonline.com/{tenant-id}/v2.0
export OIDC_AUDIENCE=api://your-app-id

Environment Variables

HTTP Server Configuration

Variable Description Default Required
MCP_TRANSPORT Transport mode stdio Yes (set to http)
MCP_HTTP_PORT HTTP server port 8080 No

OAuth Configuration

Variable Description Default Required
OAUTH_ENABLED Enable OAuth false Yes
OAUTH_MODE Mode: native or proxy native No
OAUTH_PROVIDER Provider: hmac, okta, google, azuread okta No
OAUTH_SERVER_URL Full server URL - Yes

OIDC Configuration

Variable Description Required
OIDC_ISSUER OAuth issuer URL Yes
OIDC_AUDIENCE OAuth audience Yes
OIDC_CLIENT_ID OAuth client ID Proxy mode only
OIDC_CLIENT_SECRET OAuth client secret Proxy mode only

Proxy Mode Only

Variable Description Required
OAUTH_REDIRECT_URIS Comma-separated redirect URIs Yes
JWT_SECRET JWT signing secret Yes

OAuth Endpoints

When OAuth is enabled, the following endpoints are automatically registered:

Discovery Endpoints

Proxy Mode Endpoints

MCP Endpoint

Testing OAuth

Local Testing with HMAC Provider

The HMAC provider is perfect for local development without external dependencies:

# Start server with HMAC OAuth
export MCP_TRANSPORT=http
export MCP_HTTP_PORT=8080
export OAUTH_ENABLED=true
export OAUTH_PROVIDER=hmac
export OAUTH_MODE=native
export OAUTH_SERVER_URL=http://localhost:8080
export OIDC_ISSUER=http://localhost:8080
export OIDC_AUDIENCE=api://kafka-mcp-server
export JWT_SECRET=$(openssl rand -hex 32)
export KAFKA_BROKERS=localhost:9092

./bin/kafka-mcp-server

Check OAuth metadata:

curl http://localhost:8080/.well-known/oauth-authorization-server | jq

Expected output:

{
  "issuer": "http://localhost:8080",
  "authorization_endpoint": "http://localhost:8080/oauth/authorize",
  "token_endpoint": "http://localhost:8080/oauth/token",
  "jwks_uri": "http://localhost:8080/.well-known/jwks.json",
  ...
}

Testing with Token

# Generate test token (implementation-specific)
TOKEN="your-bearer-token"

# Access MCP endpoint with token
curl -H "Authorization: Bearer $TOKEN" http://localhost:8080/mcp

Security Considerations

Production Requirements

  1. TLS/HTTPS Required: Always use TLS in production
    • Handle TLS at proxy/load balancer level
    • Set OAUTH_SERVER_URL to HTTPS URL
  2. Secrets Management: Never commit secrets to version control
    • Use secret management systems (Vault, AWS Secrets Manager)
    • Rotate JWT secrets regularly
    • Store client secrets securely
  3. Token Security:
    • Library caches validated tokens for 5 minutes
    • Tokens must be sent in Authorization header
    • Invalid/expired tokens are rejected automatically
  4. Logging: OAuth tokens and secrets are never logged

Environment-Specific Recommendations

Development:

Staging:

Production:

Troubleshooting

Server Fails to Start

Issue: failed to setup OAuth

Solutions:

  1. Verify all required environment variables are set
  2. Check OIDC_ISSUER is a valid URL
  3. For proxy mode, ensure CLIENT_ID, CLIENT_SECRET, and JWT_SECRET are set
  4. Review server logs for specific error messages

OAuth Endpoints Return 404

Issue: OAuth discovery endpoints not found

Solutions:

  1. Verify OAUTH_ENABLED=true
  2. Confirm MCP_TRANSPORT=http
  3. Check server logs for “OAuth configured” message
  4. Ensure server started successfully

Token Validation Fails

Issue: Valid tokens are rejected

Solutions:

  1. Verify token is sent in Authorization header: Authorization: Bearer <token>
  2. Check issuer in token claims matches OIDC_ISSUER
  3. Verify audience in token claims matches OIDC_AUDIENCE
  4. Ensure OAuth provider is accessible from server
  5. Check token has not expired
  6. Review server logs for validation error details

Graceful Shutdown Issues

Issue: Server doesn’t shutdown cleanly

Solutions:

  1. Ensure server receives SIGINT/SIGTERM signal
  2. Check for context cancellation in logs
  3. Default shutdown timeout is 5 seconds
  4. Review server logs for shutdown errors

Code Examples

Accessing User Context in Tools

When OAuth is enabled, authenticated user information is available in tool handlers:

import (
    oauth "github.com/tuannvm/oauth-mcp-proxy"
)

func myToolHandler(ctx context.Context, request ToolRequest) (*ToolResponse, error) {
    // Extract authenticated user from context
    user, ok := oauth.GetUserFromContext(ctx)
    if !ok {
        return nil, fmt.Errorf("authentication required")
    }

    slog.Info("Tool accessed by authenticated user",
        "username", user.Username,
        "email", user.Email,
        "subject", user.Subject)

    // Proceed with tool logic
    // ...
}

Custom OAuth Configuration

For advanced use cases, you can customize OAuth behavior by modifying internal/mcp/server.go:

// Example: Add custom logger
oauthConfig.Logger = customLogger

// Example: Customize provider-specific settings
if cfg.OAuthProvider == "okta" {
    // Provider-specific configuration
}

Migration Guide

From STDIO to HTTP with OAuth

Step 1: Ensure backwards compatibility

# Existing STDIO configuration still works
export MCP_TRANSPORT=stdio
export KAFKA_BROKERS=localhost:9092

Step 2: Add HTTP transport without OAuth

export MCP_TRANSPORT=http
export MCP_HTTP_PORT=8080
export KAFKA_BROKERS=localhost:9092

Step 3: Enable OAuth

export MCP_TRANSPORT=http
export MCP_HTTP_PORT=8080
export OAUTH_ENABLED=true
export OAUTH_MODE=native
export OAUTH_PROVIDER=okta
export OAUTH_SERVER_URL=https://your-domain.com
export OIDC_ISSUER=https://company.okta.com
export OIDC_AUDIENCE=api://kafka-mcp-server
export KAFKA_BROKERS=localhost:9092

Step 4: Update MCP clients

References

Support

For OAuth-related issues:

  1. Check server logs for detailed error messages
  2. Review oauth-mcp-proxy documentation
  3. Consult provider-specific setup guides (Okta, Google, Azure AD)
  4. Open an issue on GitHub with relevant logs (redact secrets!)