HMAC Provider Guide
Overview
HMAC provider uses shared secret JWT validation with HS256 algorithm. Best for testing, development, and service-to-service authentication.
When to Use
✅ Good for:
Local development and testing
Service-to-service authentication
Simple deployments without external OAuth provider
Full control over token generation
❌ Not ideal for:
User authentication (no SSO)
Public-facing applications (secret distribution problem)
Multi-tenant applications
Configuration
oauth.WithOAuth(mux, &oauth.Config{
Provider: "hmac",
Audience: "api://my-mcp-server", // Your server's identifier
JWTSecret: []byte("your-secret-key"), // 32+ bytes recommended
})
Required Fields
Provider: "hmac"
- Use HMAC validatorAudience
- Must match theaud
claim in tokensJWTSecret
- Shared secret for signing/verifying tokens (32+ bytes recommended)
Token Generation
Generate tokens using github.com/golang-jwt/jwt/v5
:
import "github.com/golang-jwt/jwt/v5"
func generateToken(secret []byte, audience string) string {
token := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims{
"sub": "user-123", // Subject (user ID)
"email": "[email protected]", // Email
"preferred_username": "john.doe", // Username
"aud": audience, // Must match Config.Audience
"iss": "https://your-server.com",// Issuer
"exp": time.Now().Add(time.Hour).Unix(),
"iat": time.Now().Unix(),
})
tokenString, _ := token.SignedString(secret)
return tokenString
}
Required JWT Claims
sub
- Subject (user identifier)aud
- Audience (must matchConfig.Audience
)exp
- Expiration (Unix timestamp)iat
- Issued at (Unix timestamp)
Optional Claims (extracted if present)
email
- User's emailpreferred_username
- Username (falls back toemail
orsub
)
Security Considerations
Secret Management
# Store secret in environment variable
export JWT_SECRET="your-long-random-secret-key-min-32-bytes"
// Load from environment
secret := []byte(os.Getenv("JWT_SECRET"))
if len(secret) < 32 {
log.Fatal("JWT_SECRET must be at least 32 bytes")
}
oauth.WithOAuth(mux, &oauth.Config{
Provider: "hmac",
Audience: "api://my-server",
JWTSecret: secret,
})
Secret Strength
Minimum: 32 bytes (256 bits)
Recommended: Generate with
crypto/rand
Never: Use passwords, dictionary words, or predictable values
// Generate secure secret
secret := make([]byte, 32)
if _, err := rand.Read(secret); err != nil {
log.Fatal(err)
}
fmt.Printf("Secret (base64): %s\n", base64.StdEncoding.EncodeToString(secret))
Token Expiration
Recommended: 1 hour for user tokens
Service tokens: Up to 24 hours
Always include
exp
claim
Testing
1. Start Your MCP Server
export JWT_SECRET="test-secret-key-must-be-32-bytes-long!"
go run main.go
2. Generate Test Token
token := generateToken(
[]byte("test-secret-key-must-be-32-bytes-long!"),
"api://my-mcp-server",
)
fmt.Println("Token:", token)
3. Test Authentication
curl -X POST http://localhost:8080/mcp \
-H "Authorization: Bearer <token>" \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"hello","arguments":{}}}'
Example
See examples/simple/main.go for a complete working example with HMAC provider.
Limitations
No built-in user management (you generate tokens)
Secret must be shared with all token generators
No automatic token refresh
Not suitable for public clients (secret exposure risk)
For user authentication with SSO, consider Okta, Google, or Azure providers.
Last updated
Was this helpful?