Claude Plugins Authentication Patterns: 9 MCP Security Methods Explained

Claude plugins support nine distinct authentication patterns ranging from automatic OAuth 2.0 flows to dynamic HMAC signing, all configured via the MCP (Claude-Code Plugin) server specification in plugin.json or .mcp.json manifests.

The anthropics/claude-plugins-official repository defines a flexible authentication model that lets plugin authors choose the most appropriate security pattern for their external service integrations. These patterns are documented in the canonical reference at plugins/plugin-dev/skills/mcp-integration/references/authentication.md and implemented through environment variable interpolation, header configuration, or executable helper scripts.

OAuth 2.0 (Automatic Flow)

For services that expose standard OAuth 2.0 endpoints—such as Asana, Google, or GitHub—Claude Code handles the entire authentication lifecycle automatically.

When a plugin declares an SSE or HTTP service without explicit headers, Claude Code detects the authentication requirement, launches a browser for user consent, and securely stores and refreshes tokens. No credentials appear in the JSON configuration.

{
  "service": {
    "type": "sse",
    "url": "https://mcp.asana.com/sse"
  }
}

As implemented in the Slack plugin configuration (external_plugins/slack/.mcp.json), this pattern requires zero auth fields in the manifest.

Bearer Token Authentication

Typical REST or WebSocket APIs that accept Authorization: Bearer <token> headers use environment variable interpolation. The token is stored in the user's shell environment and referenced via ${VAR} syntax in the headers section.

{
  "api": {
    "type": "http",
    "url": "https://api.example.com/mcp",
    "headers": {
      "Authorization": "Bearer ${API_TOKEN}"
    }
  }
}
export API_TOKEN="sk_live_abcdef123456"

API Key and Custom Header Authentication

Services requiring non-standard headers—such as X-API-Key or X-API-Secret—use the same interpolation pattern with explicit header names.

{
  "api": {
    "type": "http",
    "url": "https://api.example.com/mcp",
    "headers": {
      "X-API-Key": "${API_KEY}",
      "X-API-Secret": "${API_SECRET}"
    }
  }
}
export API_KEY="my_key"
export API_SECRET="my_secret"

This pattern extends to multi-header schemes for tenant-aware or user-specific contexts:

{
  "service": {
    "type": "sse",
    "url": "https://mcp.example.com/sse",
    "headers": {
      "X-Auth-Token": "${AUTH_TOKEN}",
      "X-User-ID": "${USER_ID}",
      "X-Tenant-ID": "${TENANT_ID}"
    }
  }
}

Environment Variable Injection for StdIO Servers

Plugins that run local executables (stdio transport) pass credentials via the env block. This maps environment variables to the spawned process without exposing values in the command line.

{
  "database": {
    "command": "python",
    "args": ["-m", "mcp_server_db"],
    "env": {
      "DATABASE_URL": "${DATABASE_URL}",
      "DB_USER": "${DB_USER}",
      "DB_PASSWORD": "${DB_PASSWORD}"
    }
  }
}
export DATABASE_URL="postgresql://localhost/mydb"
export DB_USER="myuser"
export DB_PASSWORD="mypassword"

Dynamic Header Helpers and Script-Based Auth

For tokens that rotate frequently or require computation—such as short-lived JWTs or HMAC signatures—the headersHelper field executes a script at request time. The script outputs a JSON object that Claude Code merges into the request headers.

JWT Generation

A helper script generates signed tokens on-the-fly:

#!/bin/bash
JWT=$(jwt-cli encode --secret "$JWT_SECRET" '{"sub":"service"}')
cat <<EOF
{ "Authorization": "Bearer $JWT" }
EOF

The plugin.json references this script using the ${CLAUDE_PLUGIN_ROOT} variable:

{
  "api": {
    "type": "http",
    "url": "https://api.example.com",
    "headersHelper": "${CLAUDE_PLUGIN_ROOT}/scripts/generate-jwt.sh"
  }
}

HMAC-Signed Requests

Payment gateways and enterprise APIs often require timestamped signatures. The helper script constructs X-Timestamp and X-Signature headers using a shared secret:

#!/bin/bash
TIMESTAMP=$(date -Iseconds)
SIGNATURE=$(echo -n "$TIMESTAMP" | openssl dgst -sha256 -hmac "$SECRET_KEY" | cut -d' ' -f2)
cat <<EOF
{
  "X-Timestamp": "$TIMESTAMP",
  "X-Signature": "$SIGNATURE",
  "X-API-Key": "$API_KEY"
}
EOF
{
  "api": {
    "type": "http",
    "url": "https://api.example.com",
    "headersHelper": "${CLAUDE_PLUGIN_ROOT}/scripts/generate-hmac.sh"
  }
}

Dynamic helpers also support refresh workflows, where the script first obtains a new token from an auth endpoint:

#!/bin/bash
TOKEN=$(curl -s -X POST https://auth.example.com/refresh -d client_id=$CLIENT_ID)
cat <<EOF
{
  "Authorization": "Bearer $TOKEN",
  "X-Timestamp": "$(date -Iseconds)"
}
EOF

Mutual TLS (mTLS) Workaround

Enterprise services requiring client certificates are not directly supported in MCP JSON transport. Instead, plugins wrap the TLS handshake in a local stdio server that proxies requests.

{
  "secure-api": {
    "command": "${CLAUDE_PLUGIN_ROOT}/servers/mtls-wrapper",
    "args": ["--cert", "${CLIENT_CERT}", "--key", "${CLIENT_KEY}"],
    "env": {
      "API_URL": "https://secure.example.com"
    }
  }
}

The wrapper executable handles the mTLS connection and exposes a plain HTTP interface to the Claude Code plugin logic.

Summary

  • OAuth (automatic): Zero-config authentication for standard OAuth 2.0 providers; Claude Code manages tokens and refresh cycles.
  • Bearer tokens: Environment variable interpolation into the Authorization header using ${API_TOKEN} syntax.
  • Custom API keys: Support for arbitrary header names (e.g., X-API-Key) via the headers configuration block.
  • StdIO environment injection: Secure credential passing to local subprocesses through the env map in plugin.json.
  • Dynamic headers: Executable scripts referenced by headersHelper generate JWTs, HMAC signatures, or refresh tokens at request time.
  • mTLS: Achieved through stdio wrapper scripts that terminate TLS client certificate authentication locally.

Frequently Asked Questions

How do I choose between OAuth and bearer tokens for my Claude plugin?

Use OAuth (automatic) when integrating with public SaaS platforms like GitHub, Google, or Asana that support standard OAuth 2.0 flows. This pattern requires no user configuration beyond the initial consent screen. Use bearer tokens or API keys for private APIs, internal services, or when you need to control token lifecycle manually via environment variables.

Can I rotate API keys without restarting Claude Code?

Yes, when using the headersHelper pattern. Instead of static environment variable interpolation, configure a script that generates or retrieves fresh tokens at request time. Claude Code executes this helper before each request, allowing dynamic rotation without restarting the client or reloading the plugin manifest.

Where should I document required environment variables for my plugin?

Document all required environment variables in your plugin's README.md. According to the repository conventions, each plugin should list the exact variable names (e.g., DATABASE_URL, API_KEY) and whether they are required for OAuth, stdIO, or HTTP header authentication. The plugins/plugin-dev/skills/mcp-integration/references/authentication.md file provides the canonical reference for these documentation standards.

Is mTLS natively supported in Claude plugin configurations?

No, native mTLS is not supported in the MCP JSON transport. You must implement a stdio wrapper server that handles the TLS handshake with client certificates, then forward the request over plain HTTP to the Claude Code plugin. Pass certificate paths via the args or env fields in the server configuration.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →