> ## Documentation Index
> Fetch the complete documentation index at: https://praison.ai/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# MCP Authentication

> OAuth 2.1, OIDC Discovery, and API Key authentication per MCP 2025-11-25

# MCP Authentication

PraisonAI MCP Server supports multiple authentication methods per the MCP 2025-11-25 specification, including OAuth 2.1 with PKCE, OpenID Connect Discovery, and API Key authentication.

## Protocol Version

This feature implements **MCP Protocol Version 2025-11-25**.

## Authentication Methods

| Method         | Description                   | Use Case                    |
| -------------- | ----------------------------- | --------------------------- |
| OAuth 2.1      | Full OAuth flow with PKCE     | Web applications, user auth |
| OIDC Discovery | Auto-discover OAuth endpoints | Enterprise SSO              |
| API Key        | Simple bearer token           | CLI tools, scripts          |

## Python API

### OIDC Discovery

```python theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
import asyncio
from praisonai.mcp_server.auth.oidc import OIDCDiscovery

async def main():
    discovery = OIDCDiscovery()
    
    # Discover from any OIDC provider
    config = await discovery.discover("https://accounts.google.com")
    
    if config:
        print(f"Issuer: {config.issuer}")
        print(f"Auth endpoint: {config.authorization_endpoint}")
        print(f"Token endpoint: {config.token_endpoint}")
        print(f"JWKS URI: {config.jwks_uri}")

asyncio.run(main())
```

### OAuth 2.1 with PKCE

```python theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
from praisonai.mcp_server.auth.oauth import OAuthConfig, OAuthManager

# Configure OAuth
config = OAuthConfig(
    authorization_endpoint="https://auth.example.com/authorize",
    token_endpoint="https://auth.example.com/token",
    client_id="my-mcp-client",
    default_scopes=["openid", "profile", "tools:read"],
    use_pkce=True,  # Required for OAuth 2.1
)

oauth = OAuthManager(config)

# Create authorization URL with PKCE
auth_url, auth_request = oauth.create_authorization_url(
    scopes=["openid", "profile", "tools:call"],
)

print(f"Auth URL: {auth_url}")
print(f"State: {auth_request.state}")
print(f"Code verifier: {auth_request.code_verifier}")
print(f"Code challenge: {auth_request.code_challenge}")

# After user authorizes, exchange code for token
# token = await oauth.exchange_code(code, auth_request)
```

### API Key Authentication

```python theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
from praisonai.mcp_server.auth.api_key import APIKeyAuth

api_key_auth = APIKeyAuth()

# Generate a new API key
raw_key, api_key = api_key_auth.generate_key(
    name="my-api-key",
    scopes=["tools:read", "tools:call", "resources:read"],
)

print(f"Key: {raw_key}")  # mcp_xxx... (store securely!)
print(f"Key ID: {api_key.key_id}")
print(f"Scopes: {api_key.scopes}")

# Validate a key
is_valid, validated_key = api_key_auth.validate(raw_key)
print(f"Valid: {is_valid}")

# Validate from Authorization header
is_valid, key = api_key_auth.validate_header("Bearer mcp_xxx...")
```

### Scope Management

```python theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
from praisonai.mcp_server.auth.scopes import ScopeManager

scope_manager = ScopeManager()

# Check if required scopes are granted
required = ["tools:read"]
granted = ["tools:call"]  # tools:call implies tools:read

is_valid, challenge = scope_manager.validate_scopes(required, granted)
print(f"Valid: {is_valid}")

# Expand scopes (show implied scopes)
expanded = scope_manager.expand_scopes(["tools:call"])
print(f"Expanded: {expanded}")  # {'tools:call', 'tools:read'}

# Admin scope expands to all
admin_expanded = scope_manager.expand_scopes(["admin"])
print(f"Admin expands to: {list(admin_expanded)[:5]}...")
```

## CLI Usage

### Start Server with API Key

```bash theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
praisonai mcp serve --transport http-stream --api-key YOUR_SECRET_KEY
```

### Generate API Key

```bash theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
praisonai mcp auth generate-key --name "my-key" --scopes "tools:read,tools:call"
```

### Validate API Key

```bash theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
praisonai mcp auth validate-key YOUR_KEY
```

## Available Scopes

| Scope                 | Description                   | Implies          |
| --------------------- | ----------------------------- | ---------------- |
| `tools:read`          | List and describe tools       | -                |
| `tools:call`          | Execute tools                 | `tools:read`     |
| `resources:read`      | Read resources                | -                |
| `resources:subscribe` | Subscribe to resource updates | `resources:read` |
| `prompts:read`        | List and get prompts          | -                |
| `prompts:execute`     | Execute prompts               | `prompts:read`   |
| `tasks:read`          | View tasks                    | -                |
| `tasks:write`         | Create/cancel tasks           | `tasks:read`     |
| `admin`               | Full access                   | All scopes       |

## WWW-Authenticate Challenge

```python theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
challenge = oauth.create_www_authenticate_challenge(
    required_scopes=["admin"],
    error="insufficient_scope",
    error_description="Admin access required",
)
# Bearer scope="admin", error="insufficient_scope", error_description="Admin access required"
```

## Security Best Practices

1. **Always use PKCE** - Required for OAuth 2.1
2. **Validate origins** - Use `--allowed-origins` for HTTP transport
3. **Rotate API keys** - Regularly rotate keys
4. **Minimal scopes** - Request only needed scopes
5. **Secure storage** - Never commit keys to version control

## Environment Variables

```bash theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
# OAuth configuration
export OAUTH_CLIENT_ID=your_client_id
export OAUTH_CLIENT_SECRET=your_client_secret  # Optional for public clients
export OIDC_ISSUER_URL=https://auth.example.com

# API key (for server)
export MCP_API_KEY=your_api_key
```

## Related

* [MCP Elicitation](/docs/mcp/mcp-elicitation) - URL mode for OAuth flows
* [PraisonAI MCP Server](/docs/mcp/praisonai-mcp-server) - Full documentation
* [MCP Tasks API](/docs/mcp/mcp-tasks-api) - Protected operations
