Skip to content

[STORY] OAuth 2.1 Authentication Infrastructure for MCP #478

@jsbattig

Description

@jsbattig

Part of: #477

Story: OAuth Authentication for MCP Integration

Feature Group: F1 - OAuth 2.1 Authentication Infrastructure

📖 Story Overview

User Story

As a Claude.ai user, I want to authenticate with CIDX server using OAuth 2.1 so that I can securely access code search capabilities without managing API keys.

Objective

Implement a complete OAuth 2.1 authorization server that enables Claude and other MCP clients to authenticate securely with CIDX server, providing activity-based token management for seamless long-running sessions.

User Value

  • 🔐 Secure authentication without API key management
  • ⏱️ Long-lived sessions with automatic extension (8h base + activity)
  • 🔄 Seamless token refresh without re-authentication
  • 🎯 Standard OAuth flow familiar to developers

✅ Acceptance Criteria

Feature: OAuth 2.1 Authentication for MCP Clients

  Background:
    Given the CIDX server is running
    And OAuth endpoints are configured

  Scenario: Discover OAuth endpoints
    When a client requests "/.well-known/oauth-authorization-server"
    Then the response contains authorization endpoint "/oauth/authorize"
    And the response contains token endpoint "/oauth/token"
    And the response contains registration endpoint "/oauth/register"
    And the response indicates PKCE is required
    And supported grant types include "authorization_code"

  Scenario: Dynamic client registration
    When Claude sends a registration request to "/oauth/register"
    With client name "Claude.ai MCP Client"
    And redirect URI "https://claude.ai/oauth/callback"
    Then a client_id is generated and returned
    And the client is stored in OAuth database
    And the response includes client_id and registration metadata

  Scenario: Authorization code flow with PKCE
    Given a registered OAuth client exists
    When the client initiates authorization with:
      | client_id       | generated_client_id |
      | redirect_uri    | registered_uri      |
      | code_challenge  | valid_pkce_challenge|
      | response_type   | code                |
      | state          | random_state        |
    Then user is redirected to login page
    When user successfully authenticates
    Then authorization code is generated
    And user is redirected to callback with code and state

  Scenario: Token exchange with PKCE verification
    Given a valid authorization code exists
    When client exchanges code for token with:
      | grant_type     | authorization_code  |
      | code          | valid_auth_code     |
      | code_verifier | matching_verifier   |
      | client_id     | registered_client   |
    Then access token is generated with 8-hour expiration
    And refresh token is generated with 30-day expiration
    And tokens are associated with authenticated user
    And response includes token_type "Bearer"

  Scenario: Activity-based token extension
    Given a valid access token with 3 hours remaining
    When the token is used for an API request
    Then the token expiration extends by 8 hours
    And the new expiration is capped at 30 days from creation
    And the extension is recorded in the database

  Scenario: Token validation for MCP requests
    Given a request to "/mcp" endpoint
    When the request includes "Authorization: Bearer <token>"
    Then the token is validated against OAuth storage
    And user context is extracted from token
    And permissions are loaded from UserManager
    And request proceeds if token is valid

  Scenario: Handle expired tokens
    Given an expired access token
    When the token is used for an API request
    Then the response returns 401 Unauthorized
    And error indicates "token_expired"
    And client must use refresh token or re-authenticate

🔧 Technical Requirements

Database Schema (SQLite)

-- pseudocode schema
TABLE oauth_clients (
    client_id TEXT PRIMARY KEY,
    client_name TEXT NOT NULL,
    redirect_uris JSON NOT NULL,
    created_at TIMESTAMP,
    metadata JSON
)

TABLE oauth_codes (
    code TEXT PRIMARY KEY,
    client_id TEXT REFERENCES oauth_clients,
    user_id TEXT NOT NULL,
    code_challenge TEXT NOT NULL,
    redirect_uri TEXT NOT NULL,
    expires_at TIMESTAMP,
    used BOOLEAN DEFAULT FALSE
)

TABLE oauth_tokens (
    token_id TEXT PRIMARY KEY,
    client_id TEXT REFERENCES oauth_clients,
    user_id TEXT NOT NULL,
    access_token TEXT UNIQUE NOT NULL,
    refresh_token TEXT UNIQUE,
    expires_at TIMESTAMP,
    created_at TIMESTAMP,
    last_activity TIMESTAMP,
    hard_expires_at TIMESTAMP
)

API Endpoints

# pseudocode endpoints
GET /.well-known/oauth-authorization-server
    returns: OAuth discovery metadata

POST /oauth/register
    body: {client_name, redirect_uris, grant_types}
    returns: {client_id, client_secret_expires_at: 0}

GET /oauth/authorize
    params: client_id, redirect_uri, response_type, code_challenge, state
    returns: redirect to login or consent page

POST /oauth/token
    body: {grant_type, code?, code_verifier?, refresh_token?}
    returns: {access_token, token_type, expires_in, refresh_token}

Token Management Logic

# pseudocode for activity extension
def extend_token_on_activity(token):
    remaining = token.expires_at - now()
    if remaining < 4_hours:
        new_expiry = now() + 8_hours
        max_expiry = token.created_at + 30_days
        token.expires_at = min(new_expiry, max_expiry)
        token.last_activity = now()
        save_token(token)

Integration Points

  • UserManager: Validate credentials during authorization
  • FastAPI: Mount OAuth routes in main app
  • Auth Middleware: Extend to support Bearer tokens
  • SQLite Storage: Atomic transactions for token operations

📋 Implementation Checklist

Setup & Configuration

  • Install authlib>=1.3.0 and aiosqlite>=0.19.0
  • Create OAuth module at /src/code_indexer/server/auth/oauth/
  • Initialize SQLite database at ~/.cidx-server/oauth.db
  • Configure OAuth server settings (issuer URL, algorithms)

OAuth Server Implementation

  • Implement OAuthManager class with Authlib
  • Create SQLite storage layer with async operations
  • Implement discovery endpoint (.well-known)
  • Implement dynamic client registration
  • Implement authorization endpoint with login integration
  • Implement token endpoint with PKCE validation
  • Implement token introspection (optional but recommended)

Security Implementation

  • Enforce PKCE for all authorization flows
  • Generate cryptographically secure tokens (secrets.token_urlsafe)
  • Implement CSRF protection for authorization
  • Add rate limiting for token endpoints
  • Implement secure token storage with hashing

Token Management

  • Implement 8-hour initial expiration
  • Implement activity-based extension logic
  • Implement 30-day hard expiration limit
  • Create token cleanup job for expired tokens
  • Add token revocation endpoint

Integration

  • Modify auth dependencies to support Bearer tokens
  • Create unified auth middleware for JWT/OAuth
  • Update UserManager integration
  • Mount OAuth routes in FastAPI app
  • Update CORS settings for OAuth redirects

🧪 Testing Requirements

Unit Tests

  • Test OAuth discovery endpoint
  • Test client registration validation
  • Test PKCE generation and validation
  • Test authorization code generation
  • Test token exchange with various grant types
  • Test activity-based extension logic
  • Test token expiration boundaries

Integration Tests

  • Test complete OAuth flow end-to-end
  • Test Bearer token validation in API calls
  • Test token extension during API activity
  • Test expired token handling
  • Test refresh token flow
  • Test concurrent token operations

Security Tests

  • Test PKCE requirement enforcement
  • Test authorization code replay prevention
  • Test token uniqueness
  • Test SQL injection prevention
  • Test CSRF protection

Performance Tests

  • Test token validation speed (<5ms)
  • Test concurrent authorization flows
  • Test database lock handling
  • Test token cache effectiveness

📝 Definition of Done

  • All OAuth 2.1 endpoints implemented and functional
  • PKCE validation working and required
  • Activity-based token extension working (8h + activity, 30d max)
  • SQLite storage layer operational with migrations
  • Integration with existing UserManager complete
  • Bearer token validation in auth middleware
  • All unit tests passing (>90% coverage)
  • Integration tests passing with Claude.ai simulator
  • Security audit completed (OWASP compliance)
  • Performance targets met (<5ms token validation)
  • Documentation complete (setup, configuration, API reference)
  • Error handling comprehensive with proper status codes
  • Logging implemented for security events
  • Database cleanup job scheduled

Story Metadata:

  • Type: Feature
  • Priority: Critical (BLOCKER for other stories)
  • Points: 8
  • Components: Authentication, OAuth, Security
  • Labels: story, oauth, authentication, mcp-integration
  • Dependencies: None (foundational)
  • Blocked By: None
  • Blocks: All other MCP stories

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions