spacehub

surshar / claude-code

Claude Code is an agentic coding tool that lives in your terminal, understands your codebase, and helps you code faster by executing routine tasks, explaining complex code, and handling git workflows - all through natural language commands.

Built by Anthropic · github.com/anthropics

claude-code / plugins / plugin-dev / skills / mcp-integration / references / authentication.md
549 lines · 10.0 KBPreviewCodeRaw
1# MCP Authentication Patterns
2
3Complete guide to authentication methods for MCP servers in Claude Code plugins.
4
5## Overview
6
7MCP 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.
8
9## OAuth (Automatic)
10
11### How It Works
12
13Claude Code automatically handles the complete OAuth 2.0 flow for SSE and HTTP servers:
14
151. User attempts to use MCP tool
162. Claude Code detects authentication needed
173. Opens browser for OAuth consent
184. User authorizes in browser
195. Tokens stored securely by Claude Code
206. Automatic token refresh
21
22### Configuration
23
24```json
25{
26 "service": {
27 "type": "sse",
28 "url": "https://mcp.example.com/sse"
29 }
30}
31```
32
33No additional auth configuration needed! Claude Code handles everything.
34
35### Supported Services
36
37**Known OAuth-enabled MCP servers:**
38- Asana: `https://mcp.asana.com/sse`
39- GitHub (when available)
40- Google services (when available)
41- Custom OAuth servers
42
43### OAuth Scopes
44
45OAuth scopes are determined by the MCP server. Users see required scopes during the consent flow.
46
47**Document required scopes in your README:**
48```markdown
49## Authentication
50
51This plugin requires the following Asana permissions:
52- Read tasks and projects
53- Create and update tasks
54- Access workspace data
55```
56
57### Token Storage
58
59Tokens are stored securely by Claude Code:
60- Not accessible to plugins
61- Encrypted at rest
62- Automatic refresh
63- Cleared on sign-out
64
65### Troubleshooting OAuth
66
67**Authentication loop:**
68- Clear cached tokens (sign out and sign in)
69- Check OAuth redirect URLs
70- Verify server OAuth configuration
71
72**Scope issues:**
73- User may need to re-authorize for new scopes
74- Check server documentation for required scopes
75
76**Token expiration:**
77- Claude Code auto-refreshes
78- If refresh fails, prompts re-authentication
79
80## Token-Based Authentication
81
82### Bearer Tokens
83
84Most common for HTTP and WebSocket servers.
85
86**Configuration:**
87```json
88{
89 "api": {
90 "type": "http",
91 "url": "https://api.example.com/mcp",
92 "headers": {
93 "Authorization": "Bearer ${API_TOKEN}"
94 }
95 }
96}
97```
98
99**Environment variable:**
100```bash
101export API_TOKEN="your-secret-token-here"
102```
103
104### API Keys
105
106Alternative to Bearer tokens, often in custom headers.
107
108**Configuration:**
109```json
110{
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```
121
122### Custom Headers
123
124Services may use custom authentication headers.
125
126**Configuration:**
127```json
128{
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```
140
141### Documenting Token Requirements
142
143Always document in your README:
144
145```markdown
146## Setup
147
148### Required Environment Variables
149
150Set these environment variables before using the plugin:
151
152\`\`\`bash
153export API_TOKEN="your-token-here"
154export API_SECRET="your-secret-here"
155\`\`\`
156
157### Obtaining Tokens
158
1591. Visit https://api.example.com/tokens
1602. Create a new API token
1613. Copy the token and secret
1624. Set environment variables as shown above
163
164### Token Permissions
165
166The API token needs the following permissions:
167- Read access to resources
168- Write access for creating items
169- Delete access (optional, for cleanup operations)
170\`\`\`
171```
172
173## Environment Variable Authentication (stdio)
174
175### Passing Credentials to Server
176
177For stdio servers, pass credentials via environment variables:
178
179```json
180{
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```
192
193### User Environment Variables
194
195```bash
196# User sets these in their shell
197export DATABASE_URL="postgresql://localhost/mydb"
198export DB_USER="myuser"
199export DB_PASSWORD="mypassword"
200```
201
202### Documentation Template
203
204```markdown
205## Database Configuration
206
207Set these environment variables:
208
209\`\`\`bash
210export DATABASE_URL="postgresql://host:port/database"
211export DB_USER="username"
212export DB_PASSWORD="password"
213\`\`\`
214
215Or create a `.env` file (add to `.gitignore`):
216
217\`\`\`
218DATABASE_URL=postgresql://localhost:5432/mydb
219DB_USER=myuser
220DB_PASSWORD=mypassword
221\`\`\`
222
223Load with: \`source .env\` or \`export $(cat .env | xargs)\`
224\`\`\`
225```
226
227## Dynamic Headers
228
229### Headers Helper Script
230
231For tokens that change or expire, use a helper script:
232
233```json
234{
235 "api": {
236 "type": "sse",
237 "url": "https://api.example.com",
238 "headersHelper": "${CLAUDE_PLUGIN_ROOT}/scripts/get-headers.sh"
239 }
240}
241```
242
243**Script (get-headers.sh):**
244```bash
245#!/bin/bash
246# Generate dynamic authentication headers
247
248# Fetch fresh token
249TOKEN=$(get-fresh-token-from-somewhere)
250
251# Output JSON headers
252cat <<EOF
253{
254 "Authorization": "Bearer $TOKEN",
255 "X-Timestamp": "$(date -Iseconds)"
256}
257EOF
258```
259
260### Use Cases for Dynamic Headers
261
262- Short-lived tokens that need refresh
263- Tokens with HMAC signatures
264- Time-based authentication
265- Dynamic tenant/workspace selection
266
267## Security Best Practices
268
269### DO
270
271✅ **Use environment variables:**
272```json
273{
274 "headers": {
275 "Authorization": "Bearer ${API_TOKEN}"
276 }
277}
278```
279
280✅ **Document required variables in README**
281
282✅ **Use HTTPS/WSS always**
283
284✅ **Implement token rotation**
285
286✅ **Store tokens securely (env vars, not files)**
287
288✅ **Let OAuth handle authentication when available**
289
290### DON'T
291
292❌ **Hardcode tokens:**
293```json
294{
295 "headers": {
296 "Authorization": "Bearer sk-abc123..." // NEVER!
297 }
298}
299```
300
301❌ **Commit tokens to git**
302
303❌ **Share tokens in documentation**
304
305❌ **Use HTTP instead of HTTPS**
306
307❌ **Store tokens in plugin files**
308
309❌ **Log tokens or sensitive headers**
310
311## Multi-Tenancy Patterns
312
313### Workspace/Tenant Selection
314
315**Via environment variable:**
316```json
317{
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```
328
329**Via URL:**
330```json
331{
332 "api": {
333 "type": "http",
334 "url": "https://${TENANT_ID}.api.example.com/mcp"
335 }
336}
337```
338
339### Per-User Configuration
340
341Users set their own workspace:
342
343```bash
344export WORKSPACE_ID="my-workspace-123"
345export TENANT_ID="my-company"
346```
347
348## Authentication Troubleshooting
349
350### Common Issues
351
352**401 Unauthorized:**
353- Check token is set correctly
354- Verify token hasn't expired
355- Check token has required permissions
356- Ensure header format is correct
357
358**403 Forbidden:**
359- Token valid but lacks permissions
360- Check scope/permissions
361- Verify workspace/tenant ID
362- May need admin approval
363
364**Token not found:**
365```bash
366# Check environment variable is set
367echo $API_TOKEN
368
369# If empty, set it
370export API_TOKEN="your-token"
371```
372
373**Token in wrong format:**
374```json
375// Correct
376"Authorization": "Bearer sk-abc123"
377
378// Wrong
379"Authorization": "sk-abc123"
380```
381
382### Debugging Authentication
383
384**Enable debug mode:**
385```bash
386claude --debug
387```
388
389Look for:
390- Authentication header values (sanitized)
391- OAuth flow progress
392- Token refresh attempts
393- Authentication errors
394
395**Test authentication separately:**
396```bash
397# Test HTTP endpoint
398curl -H "Authorization: Bearer $API_TOKEN" \
399 https://api.example.com/mcp/health
400
401# Should return 200 OK
402```
403
404## Migration Patterns
405
406### From Hardcoded to Environment Variables
407
408**Before:**
409```json
410{
411 "headers": {
412 "Authorization": "Bearer sk-hardcoded-token"
413 }
414}
415```
416
417**After:**
418```json
419{
420 "headers": {
421 "Authorization": "Bearer ${API_TOKEN}"
422 }
423}
424```
425
426**Migration steps:**
4271. Add environment variable to plugin README
4282. Update configuration to use ${VAR}
4293. Test with variable set
4304. Remove hardcoded value
4315. Commit changes
432
433### From Basic Auth to OAuth
434
435**Before:**
436```json
437{
438 "headers": {
439 "Authorization": "Basic ${BASE64_CREDENTIALS}"
440 }
441}
442```
443
444**After:**
445```json
446{
447 "type": "sse",
448 "url": "https://mcp.example.com/sse"
449}
450```
451
452**Benefits:**
453- Better security
454- No credential management
455- Automatic token refresh
456- Scoped permissions
457
458## Advanced Authentication
459
460### Mutual TLS (mTLS)
461
462Some enterprise services require client certificates.
463
464**Not directly supported in MCP configuration.**
465
466**Workaround:** Wrap in stdio server that handles mTLS:
467
468```json
469{
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```
479
480### JWT Tokens
481
482Generate JWT tokens dynamically with headers helper:
483
484```bash
485#!/bin/bash
486# generate-jwt.sh
487
488# Generate JWT (using library or API call)
489JWT=$(generate-jwt-token)
490
491echo "{\"Authorization\": \"Bearer $JWT\"}"
492```
493
494```json
495{
496 "headersHelper": "${CLAUDE_PLUGIN_ROOT}/scripts/generate-jwt.sh"
497}
498```
499
500### HMAC Signatures
501
502For APIs requiring request signing:
503
504```bash
505#!/bin/bash
506# generate-hmac.sh
507
508TIMESTAMP=$(date -Iseconds)
509SIGNATURE=$(echo -n "$TIMESTAMP" | openssl dgst -sha256 -hmac "$SECRET_KEY" | cut -d' ' -f2)
510
511cat <<EOF
512{
513 "X-Timestamp": "$TIMESTAMP",
514 "X-Signature": "$SIGNATURE",
515 "X-API-Key": "$API_KEY"
516}
517EOF
518```
519
520## Best Practices Summary
521
522### For Plugin Developers
523
5241. **Prefer OAuth** when service supports it
5252. **Use environment variables** for tokens
5263. **Document all required variables** in README
5274. **Provide setup instructions** with examples
5285. **Never commit credentials**
5296. **Use HTTPS/WSS only**
5307. **Test authentication thoroughly**
531
532### For Plugin Users
533
5341. **Set environment variables** before using plugin
5352. **Keep tokens secure** and private
5363. **Rotate tokens regularly**
5374. **Use different tokens** for dev/prod
5385. **Don't commit .env files** to git
5396. **Review OAuth scopes** before authorizing
540
541## Conclusion
542
543Choose the authentication method that matches your MCP server's requirements:
544- **OAuth** for cloud services (easiest for users)
545- **Bearer tokens** for API services
546- **Environment variables** for stdio servers
547- **Dynamic headers** for complex auth flows
548
549Always prioritize security and provide clear setup documentation for users.