Loading source
Pulling the file list, source metadata, and syntax-aware rendering for this listing.
Source from repo
Guidance for integrating MCP (Model Context Protocol) servers into Claude Code plugins.
Files
Skill
Size
Entrypoint
Format
Open file
Syntax-highlighted preview of this file as included in the skill package.
references/authentication.md
1# MCP Authentication Patterns23Complete guide to authentication methods for MCP servers in Claude Code plugins.45## Overview67MCP servers support multiple authentication methods depending on the server type and service requirements. Choose the method that best matches your use case and security requirements.89## OAuth (Automatic)1011### How It Works1213Claude Code automatically handles the complete OAuth 2.0 flow for SSE and HTTP servers:14151. User attempts to use MCP tool162. Claude Code detects authentication needed173. Opens browser for OAuth consent184. User authorizes in browser195. Tokens stored securely by Claude Code206. Automatic token refresh2122### Configuration2324```json25{26"service": {27"type": "sse",28"url": "https://mcp.example.com/sse"29}30}31```3233No additional auth configuration needed! Claude Code handles everything.3435### Supported Services3637**Known OAuth-enabled MCP servers:**38- Asana: `https://mcp.asana.com/sse`39- GitHub (when available)40- Google services (when available)41- Custom OAuth servers4243### OAuth Scopes4445OAuth scopes are determined by the MCP server. Users see required scopes during the consent flow.4647**Document required scopes in your README:**48```markdown49## Authentication5051This plugin requires the following Asana permissions:52- Read tasks and projects53- Create and update tasks54- Access workspace data55```5657### Token Storage5859Tokens are stored securely by Claude Code:60- Not accessible to plugins61- Encrypted at rest62- Automatic refresh63- Cleared on sign-out6465### Troubleshooting OAuth6667**Authentication loop:**68- Clear cached tokens (sign out and sign in)69- Check OAuth redirect URLs70- Verify server OAuth configuration7172**Scope issues:**73- User may need to re-authorize for new scopes74- Check server documentation for required scopes7576**Token expiration:**77- Claude Code auto-refreshes78- If refresh fails, prompts re-authentication7980## Token-Based Authentication8182### Bearer Tokens8384Most common for HTTP and WebSocket servers.8586**Configuration:**87```json88{89"api": {90"type": "http",91"url": "https://api.example.com/mcp",92"headers": {93"Authorization": "Bearer ${API_TOKEN}"94}95}96}97```9899**Environment variable:**100```bash101export API_TOKEN="your-secret-token-here"102```103104### API Keys105106Alternative to Bearer tokens, often in custom headers.107108**Configuration:**109```json110{111"api": {112"type": "http",113"url": "https://api.example.com/mcp",114"headers": {115"X-API-Key": "${API_KEY}",116"X-API-Secret": "${API_SECRET}"117}118}119}120```121122### Custom Headers123124Services may use custom authentication headers.125126**Configuration:**127```json128{129"service": {130"type": "sse",131"url": "https://mcp.example.com/sse",132"headers": {133"X-Auth-Token": "${AUTH_TOKEN}",134"X-User-ID": "${USER_ID}",135"X-Tenant-ID": "${TENANT_ID}"136}137}138}139```140141### Documenting Token Requirements142143Always document in your README:144145```markdown146## Setup147148### Required Environment Variables149150Set these environment variables before using the plugin:151152\`\`\`bash153export API_TOKEN="your-token-here"154export API_SECRET="your-secret-here"155\`\`\`156157### Obtaining Tokens1581591. Visit https://api.example.com/tokens1602. Create a new API token1613. Copy the token and secret1624. Set environment variables as shown above163164### Token Permissions165166The API token needs the following permissions:167- Read access to resources168- Write access for creating items169- Delete access (optional, for cleanup operations)170\`\`\`171```172173## Environment Variable Authentication (stdio)174175### Passing Credentials to Server176177For stdio servers, pass credentials via environment variables:178179```json180{181"database": {182"command": "python",183"args": ["-m", "mcp_server_db"],184"env": {185"DATABASE_URL": "${DATABASE_URL}",186"DB_USER": "${DB_USER}",187"DB_PASSWORD": "${DB_PASSWORD}"188}189}190}191```192193### User Environment Variables194195```bash196# User sets these in their shell197export DATABASE_URL="postgresql://localhost/mydb"198export DB_USER="myuser"199export DB_PASSWORD="mypassword"200```201202### Documentation Template203204```markdown205## Database Configuration206207Set these environment variables:208209\`\`\`bash210export DATABASE_URL="postgresql://host:port/database"211export DB_USER="username"212export DB_PASSWORD="password"213\`\`\`214215Or create a `.env` file (add to `.gitignore`):216217\`\`\`218DATABASE_URL=postgresql://localhost:5432/mydb219DB_USER=myuser220DB_PASSWORD=mypassword221\`\`\`222223Load with: \`source .env\` or \`export $(cat .env | xargs)\`224\`\`\`225```226227## Dynamic Headers228229### Headers Helper Script230231For tokens that change or expire, use a helper script:232233```json234{235"api": {236"type": "sse",237"url": "https://api.example.com",238"headersHelper": "${CLAUDE_PLUGIN_ROOT}/scripts/get-headers.sh"239}240}241```242243**Script (get-headers.sh):**244```bash245#!/bin/bash246# Generate dynamic authentication headers247248# Fetch fresh token249TOKEN=$(get-fresh-token-from-somewhere)250251# Output JSON headers252cat <<EOF253{254"Authorization": "Bearer $TOKEN",255"X-Timestamp": "$(date -Iseconds)"256}257EOF258```259260### Use Cases for Dynamic Headers261262- Short-lived tokens that need refresh263- Tokens with HMAC signatures264- Time-based authentication265- Dynamic tenant/workspace selection266267## Security Best Practices268269### DO270271✅ **Use environment variables:**272```json273{274"headers": {275"Authorization": "Bearer ${API_TOKEN}"276}277}278```279280✅ **Document required variables in README**281282✅ **Use HTTPS/WSS always**283284✅ **Implement token rotation**285286✅ **Store tokens securely (env vars, not files)**287288✅ **Let OAuth handle authentication when available**289290### DON'T291292❌ **Hardcode tokens:**293```json294{295"headers": {296"Authorization": "Bearer sk-abc123..." // NEVER!297}298}299```300301❌ **Commit tokens to git**302303❌ **Share tokens in documentation**304305❌ **Use HTTP instead of HTTPS**306307❌ **Store tokens in plugin files**308309❌ **Log tokens or sensitive headers**310311## Multi-Tenancy Patterns312313### Workspace/Tenant Selection314315**Via environment variable:**316```json317{318"api": {319"type": "http",320"url": "https://api.example.com/mcp",321"headers": {322"Authorization": "Bearer ${API_TOKEN}",323"X-Workspace-ID": "${WORKSPACE_ID}"324}325}326}327```328329**Via URL:**330```json331{332"api": {333"type": "http",334"url": "https://${TENANT_ID}.api.example.com/mcp"335}336}337```338339### Per-User Configuration340341Users set their own workspace:342343```bash344export WORKSPACE_ID="my-workspace-123"345export TENANT_ID="my-company"346```347348## Authentication Troubleshooting349350### Common Issues351352**401 Unauthorized:**353- Check token is set correctly354- Verify token hasn't expired355- Check token has required permissions356- Ensure header format is correct357358**403 Forbidden:**359- Token valid but lacks permissions360- Check scope/permissions361- Verify workspace/tenant ID362- May need admin approval363364**Token not found:**365```bash366# Check environment variable is set367echo $API_TOKEN368369# If empty, set it370export API_TOKEN="your-token"371```372373**Token in wrong format:**374```json375// Correct376"Authorization": "Bearer sk-abc123"377378// Wrong379"Authorization": "sk-abc123"380```381382### Debugging Authentication383384**Enable debug mode:**385```bash386claude --debug387```388389Look for:390- Authentication header values (sanitized)391- OAuth flow progress392- Token refresh attempts393- Authentication errors394395**Test authentication separately:**396```bash397# Test HTTP endpoint398curl -H "Authorization: Bearer $API_TOKEN" \399https://api.example.com/mcp/health400401# Should return 200 OK402```403404## Migration Patterns405406### From Hardcoded to Environment Variables407408**Before:**409```json410{411"headers": {412"Authorization": "Bearer sk-hardcoded-token"413}414}415```416417**After:**418```json419{420"headers": {421"Authorization": "Bearer ${API_TOKEN}"422}423}424```425426**Migration steps:**4271. Add environment variable to plugin README4282. Update configuration to use ${VAR}4293. Test with variable set4304. Remove hardcoded value4315. Commit changes432433### From Basic Auth to OAuth434435**Before:**436```json437{438"headers": {439"Authorization": "Basic ${BASE64_CREDENTIALS}"440}441}442```443444**After:**445```json446{447"type": "sse",448"url": "https://mcp.example.com/sse"449}450```451452**Benefits:**453- Better security454- No credential management455- Automatic token refresh456- Scoped permissions457458## Advanced Authentication459460### Mutual TLS (mTLS)461462Some enterprise services require client certificates.463464**Not directly supported in MCP configuration.**465466**Workaround:** Wrap in stdio server that handles mTLS:467468```json469{470"secure-api": {471"command": "${CLAUDE_PLUGIN_ROOT}/servers/mtls-wrapper",472"args": ["--cert", "${CLIENT_CERT}", "--key", "${CLIENT_KEY}"],473"env": {474"API_URL": "https://secure.example.com"475}476}477}478```479480### JWT Tokens481482Generate JWT tokens dynamically with headers helper:483484```bash485#!/bin/bash486# generate-jwt.sh487488# Generate JWT (using library or API call)489JWT=$(generate-jwt-token)490491echo "{\"Authorization\": \"Bearer $JWT\"}"492```493494```json495{496"headersHelper": "${CLAUDE_PLUGIN_ROOT}/scripts/generate-jwt.sh"497}498```499500### HMAC Signatures501502For APIs requiring request signing:503504```bash505#!/bin/bash506# generate-hmac.sh507508TIMESTAMP=$(date -Iseconds)509SIGNATURE=$(echo -n "$TIMESTAMP" | openssl dgst -sha256 -hmac "$SECRET_KEY" | cut -d' ' -f2)510511cat <<EOF512{513"X-Timestamp": "$TIMESTAMP",514"X-Signature": "$SIGNATURE",515"X-API-Key": "$API_KEY"516}517EOF518```519520## Best Practices Summary521522### For Plugin Developers5235241. **Prefer OAuth** when service supports it5252. **Use environment variables** for tokens5263. **Document all required variables** in README5274. **Provide setup instructions** with examples5285. **Never commit credentials**5296. **Use HTTPS/WSS only**5307. **Test authentication thoroughly**531532### For Plugin Users5335341. **Set environment variables** before using plugin5352. **Keep tokens secure** and private5363. **Rotate tokens regularly**5374. **Use different tokens** for dev/prod5385. **Don't commit .env files** to git5396. **Review OAuth scopes** before authorizing540541## Conclusion542543Choose the authentication method that matches your MCP server's requirements:544- **OAuth** for cloud services (easiest for users)545- **Bearer tokens** for API services546- **Environment variables** for stdio servers547- **Dynamic headers** for complex auth flows548549Always prioritize security and provide clear setup documentation for users.550