← Back to Articles
mcpauthenticationoauthapi-keyssecurity2026

How to Authenticate MCP Servers: OAuth, API Keys & Tokens (2026)

A complete guide to MCP server authentication — API keys in env vars, OAuth flows, bearer tokens, and keeping secrets out of your config files.

By Web MCP Guide•March 29, 2026•7 min read


How to Authenticate MCP Servers: OAuth, API Keys & Tokens (2026)

Most MCP servers need credentials to talk to external services — an API key for GitHub, an OAuth token for Google Drive, a bot token for Slack. Getting authentication right is both the most important and most confusing part of MCP setup for newcomers.

This guide covers every authentication pattern you'll encounter across MCP servers: API keys, OAuth tokens, environment variables, and how to keep secrets secure.

The Three Authentication Patterns

MCP servers use three main credential types:

1. API Keys — A static secret string issued by the service (GitHub PAT, OpenAI API key, etc.)
2. OAuth Access Tokens — Time-limited tokens from an OAuth flow (Google, Microsoft, Salesforce)
3. Service Account Credentials — JSON credential files (Google Cloud, GCP services)

How you pass them to the MCP server depends on the pattern.

---

Pattern 1: API Keys via Environment Variables

This is the most common pattern. The service gives you a static key; you pass it as an environment variable in your MCP config.

In Claude Desktop

{
"mcpServers": {
"github": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-github"],
"env": {
"GITHUB_PERSONAL_ACCESS_TOKEN": "ghp_yourTokenHere"
}
}
}
}

The env object in the MCP config is how you pass credentials. The server reads them as standard environment variables.

Multiple Servers with Different Keys

{
"mcpServers": {
"github": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-github"],
"env": {
"GITHUB_PERSONAL_ACCESS_TOKEN": "ghp_abc123"
}
},
"slack": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-slack"],
"env": {
"SLACK_BOT_TOKEN": "xoxb-xyz789",
"SLACK_TEAM_ID": "T1234567890"
}
}
}
}

Each server gets its own env block — they don't share credentials.

---

Pattern 2: Loading from a .env File

Hardcoding secrets in claude_desktop_config.json works, but that file is on your filesystem in plaintext. A better approach for local development: use a .env file and reference it from a wrapper script.

Create a wrapper script

~/.mcp/github-wrapper.sh:

#!/bin/bash
source ~/.mcp/.env
exec npx -y @modelcontextprotocol/server-github "$@"

~/.mcp/.env:

GITHUB_PERSONAL_ACCESS_TOKEN=ghp_yourTokenHere

Make it executable:

chmod +x ~/.mcp/github-wrapper.sh

Claude Desktop config:

{
"mcpServers": {
"github": {
"command": "/Users/yourname/.mcp/github-wrapper.sh"
}
}
}

This keeps your actual secrets out of the Claude config file.

---

Pattern 3: OAuth Access Tokens

Some services use OAuth — you complete a browser-based authorization flow and receive a time-limited access token. The MCP server then uses that token for API calls.

Google Services (Drive, Sheets, Calendar)

Google MCP servers typically use a credentials.json file from a Google Cloud service account, or an OAuth client flow.

Option A: Service Account (recommended for automation)

1. Go to Google Cloud Console
2. Create a project → Enable the API you need (Drive, Sheets, etc.)
3. Go to IAM & Admin → Service Accounts → Create service account
4. Download the JSON key file
5. Reference it in your MCP config:

{
"mcpServers": {
"gdrive": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-gdrive"],
"env": {
"GOOGLE_APPLICATION_CREDENTIALS": "/Users/yourname/.mcp/google-service-account.json"
}
}
}
}

Option B: OAuth user token

Some Google MCP servers support the OAuth user flow. Run the server once interactively:

npx @modelcontextprotocol/server-gdrive --setup

This opens a browser window, you authorize, and a token file is saved locally. Subsequent runs use the saved token (and refresh it automatically).

Microsoft / Azure Services

Microsoft MCP integrations typically use Azure AD app registration:

1. Register an app in Azure Portal → Azure Active Directory → App Registrations
2. Add API permissions for the services you need (Graph API, etc.)
3. Create a client secret
4. Pass the credentials:

{
"mcpServers": {
"microsoft": {
"command": "npx",
"args": ["-y", "@your-org/mcp-server-microsoft"],
"env": {
"AZURE_CLIENT_ID": "your-client-id",
"AZURE_CLIENT_SECRET": "your-client-secret",
"AZURE_TENANT_ID": "your-tenant-id"
}
}
}
}

---

Pattern 4: Bearer Tokens

Some APIs use a simple bearer token passed in an Authorization header. Custom MCP servers built on these APIs typically accept the token as an environment variable:

{
"mcpServers": {
"custom-api": {
"command": "node",
"args": ["/path/to/custom-mcp-server/index.js"],
"env": {
"API_BEARER_TOKEN": "Bearer your-token-here"
}
}
}
}

---

Keeping Secrets Secure

What Not to Do

āŒ Don't commit your MCP config to a public repo. The config file at ~/Library/Application Support/Claude/claude_desktop_config.json contains your API keys in plaintext. If you back up your dotfiles to GitHub, exclude this file.

Add to your .gitignore


Library/Application Support/Claude/claude_desktop_config.json

āŒ Don't share your config file directly. If someone asks "can you share your MCP config?", scrub all credentials first.

āŒ Don't use overly-permissive tokens. If your GitHub PAT only needs repo read access, don't grant it full admin rights. Scope tokens to the minimum needed.

What to Do

āœ… Use token scoping. Create tokens with minimal permissions for what the MCP server actually needs.

āœ… Rotate tokens periodically. Most services let you set expiration dates on tokens. Use them.

āœ… Use separate tokens for MCP vs other tools. If your GitHub MCP token is compromised, you don't want it to be the same token you use for CI/CD.

āœ… Store sensitive configs in a keychain-backed secret. On Mac, you can store the token in Keychain and reference it via a shell script that reads from security find-generic-password.

#!/bin/bash
export GITHUB_PERSONAL_ACCESS_TOKEN=$(security find-generic-password -a "$USER" -s "github-mcp-token" -w)
exec npx -y @modelcontextprotocol/server-github "$@"

---

Troubleshooting Authentication Errors

"Authentication failed" / 401 Unauthorized


  • The token is wrong or expired — regenerate it from the service's settings page

  • The token doesn't have the required scopes — check what permissions the MCP server needs and update accordingly

  • The env var name is wrong — check the MCP server's README for the exact variable name it expects
  • "Permission denied" / 403 Forbidden


  • The token is valid but doesn't have permission for the specific resource

  • For GitHub: the PAT may need repo scope if accessing private repos

  • For Google: the service account may need to be granted access to specific files/folders
  • Token Works in CLI but Not in MCP

    Environment variables in your shell don't automatically pass into MCP server processes — they must be explicitly listed in the env block of your MCP config. You can't rely on variables set in .bashrc or .zshrc.

    OAuth Token Expired

    OAuth access tokens typically expire after 1 hour. If your MCP server uses a stored OAuth token (common with Google integrations), look for a --refresh flag or re-run the setup flow to get a fresh token.

    ---

    Quick Reference: Common MCP Servers and Their Auth Variables

    | MCP Server | Auth Variable | Where to Get It |
    |------------|--------------|-----------------|
    | GitHub | GITHUB_PERSONAL_ACCESS_TOKEN | github.com → Settings → Developer Settings → PATs |
    | Slack | SLACK_BOT_TOKEN, SLACK_TEAM_ID | api.slack.com → Your App → OAuth & Permissions |
    | Google Drive | GOOGLE_APPLICATION_CREDENTIALS | Google Cloud Console → Service Accounts |
    | Supabase | SUPABASE_URL, SUPABASE_SERVICE_ROLE_KEY | Supabase project → Settings → API |
    | Postgres | POSTGRES_CONNECTION_STRING | Your database connection string |
    | Notion | NOTION_API_KEY | notion.so/my-integrations |
    | OpenAI | OPENAI_API_KEY | platform.openai.com → API Keys |
    | Atlassian | ATLASSIAN_API_TOKEN, ATLASSIAN_EMAIL, ATLASSIAN_BASE_URL | id.atlassian.com → Security → API Tokens |

    ---

    Related Guides


  • Debug MCP Server Issues — Full troubleshooting guide

  • MCP Security Best Practices — Deeper security coverage

  • How to Build Your First MCP Server — If you're creating a server that needs to handle auth