Add multi-user support - each API key gets own GeoGuessr session #5

Merged
NyxiumYuuki merged 1 commit from claude/add-mcp-authentication-01V5tbppGEtXc3tvjRGoTcfh into master 2025-11-29 23:43:07 +01:00
NyxiumYuuki commented 2025-11-29 23:38:26 +01:00 (Migrated from github.com)

Implements comprehensive multi-user support allowing multiple users to access the same MCP server instance with their own independent GeoGuessr accounts. Each API key now has its own session storage and context.

Multi-User Architecture

New Components

User Context System (src/geoguessr_mcp/auth/user_context.py):

  • UserContext dataclass tracks API key and associated GeoGuessr session
  • Properties for user_id, username, ncfa_cookie, is_authenticated
  • Automatically attached to each request

Multi-User Session Manager (src/geoguessr_mcp/auth/multi_user_session.py):

  • MultiUserSessionManager manages separate SessionManager per API key
  • Maps API keys to their own GeoGuessr sessions
  • Methods: get_user_context, login_user, logout_user, set_user_cookie
  • Global instance: multi_user_session_manager

Request Context (src/geoguessr_mcp/auth/request_context.py):

  • ContextVar for accessing current user context in tools
  • Functions: get_current_user_context, require_user_context, set_current_user_context
  • Enables tools to access user-specific sessions automatically

Updated Components

Authentication Middleware (src/geoguessr_mcp/middleware/auth.py):

  • Now creates user context for each authenticated request
  • Attaches context to both request.state and ContextVar
  • Supports both authenticated and unauthenticated modes
  • Default user context created when auth is disabled

Authentication Tools (src/geoguessr_mcp/tools/auth_tools.py):

  • Completely rewritten for multi-user support
  • login(): Creates session tied to caller's API key
  • logout(): Logs out only the calling user's session
  • set_ncfa_cookie(): Sets cookie for calling user only
  • get_auth_status(): Returns calling user's auth status
  • All tools use get_current_user_context() automatically

GeoGuessr Client (src/geoguessr_mcp/api/geoguessr_client.py):

  • _get_authenticated_client() checks user context first
  • Falls back to session_manager for backward compatibility
  • Automatically uses caller's session when available
  • No changes needed in services (profile, game, analysis)

How It Works

  1. User connects with API key in Authorization header
  2. Middleware validates API key and creates/retrieves UserContext
  3. UserContext attached to request.state and ContextVar
  4. Tools call get_current_user_context() to access caller's session
  5. Client automatically uses correct session for API calls
  6. Each user's session is completely isolated

Usage Example

# Configure multiple API keys
MCP_AUTH_ENABLED=true
MCP_API_KEYS=alice_key,bob_key,charlie_key

# Alice connects with: Authorization: Bearer alice_key
# Bob connects with: Authorization: Bearer bob_key
# Each can login to their own GeoGuessr account
# Sessions are completely independent

Key Features

  • Zero Interference: Users don't affect each other's sessions
  • Automatic Routing: Requests automatically use correct user's session
  • Hot Reload: Add new API keys and restart in ~2-3 seconds
  • Backward Compatible: Still works with single-user mode
  • Fallback Support: GEOGUESSR_NCFA_COOKIE still works as default

Documentation Updates

  • README.md: Added Multi-User Mode section with examples
  • README.md: Updated authentication section with multi-user details
  • README.md: Added "Adding New Users" workflow
  • Key Features section now highlights multi-user support

Technical Details

  • Uses Python ContextVar for request-scoped user context
  • Each API key gets its own SessionManager instance
  • Session storage is in-memory (persists across requests, not restarts)
  • Default cookie (GEOGUESSR_NCFA_COOKIE) used as fallback for all users
  • Fully async/await compatible throughout

Pull Request

Description

Type of Change

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • Documentation update
  • Code refactoring
  • Performance improvement
  • Test improvement

Fixes #

Changes Made

Testing Performed

  • Unit tests added/updated
  • Integration tests added/updated
  • Manual testing performed
  • All existing tests pass

Test Details

# Example test commands
pytest tests/

Screenshots (if applicable)

Checklist

  • My code follows the project's style guidelines
  • I have performed a self-review of my code
  • I have commented my code, particularly in hard-to-understand areas
  • I have made corresponding changes to the documentation
  • My changes generate no new warnings
  • I have added tests that prove my fix is effective or that my feature works
  • New and existing unit tests pass locally with my changes
  • Any dependent changes have been merged and published
  • I have checked my code and corrected any misspellings

Additional Context

Breaking Changes

Performance Impact


By submitting this pull request, I confirm that my contribution is made under the terms of the MIT License.

Implements comprehensive multi-user support allowing multiple users to access the same MCP server instance with their own independent GeoGuessr accounts. Each API key now has its own session storage and context. ## Multi-User Architecture ### New Components **User Context System** (src/geoguessr_mcp/auth/user_context.py): - UserContext dataclass tracks API key and associated GeoGuessr session - Properties for user_id, username, ncfa_cookie, is_authenticated - Automatically attached to each request **Multi-User Session Manager** (src/geoguessr_mcp/auth/multi_user_session.py): - MultiUserSessionManager manages separate SessionManager per API key - Maps API keys to their own GeoGuessr sessions - Methods: get_user_context, login_user, logout_user, set_user_cookie - Global instance: multi_user_session_manager **Request Context** (src/geoguessr_mcp/auth/request_context.py): - ContextVar for accessing current user context in tools - Functions: get_current_user_context, require_user_context, set_current_user_context - Enables tools to access user-specific sessions automatically ### Updated Components **Authentication Middleware** (src/geoguessr_mcp/middleware/auth.py): - Now creates user context for each authenticated request - Attaches context to both request.state and ContextVar - Supports both authenticated and unauthenticated modes - Default user context created when auth is disabled **Authentication Tools** (src/geoguessr_mcp/tools/auth_tools.py): - Completely rewritten for multi-user support - login(): Creates session tied to caller's API key - logout(): Logs out only the calling user's session - set_ncfa_cookie(): Sets cookie for calling user only - get_auth_status(): Returns calling user's auth status - All tools use get_current_user_context() automatically **GeoGuessr Client** (src/geoguessr_mcp/api/geoguessr_client.py): - _get_authenticated_client() checks user context first - Falls back to session_manager for backward compatibility - Automatically uses caller's session when available - No changes needed in services (profile, game, analysis) ## How It Works 1. User connects with API key in Authorization header 2. Middleware validates API key and creates/retrieves UserContext 3. UserContext attached to request.state and ContextVar 4. Tools call get_current_user_context() to access caller's session 5. Client automatically uses correct session for API calls 6. Each user's session is completely isolated ## Usage Example ```bash # Configure multiple API keys MCP_AUTH_ENABLED=true MCP_API_KEYS=alice_key,bob_key,charlie_key # Alice connects with: Authorization: Bearer alice_key # Bob connects with: Authorization: Bearer bob_key # Each can login to their own GeoGuessr account # Sessions are completely independent ``` ## Key Features - **Zero Interference**: Users don't affect each other's sessions - **Automatic Routing**: Requests automatically use correct user's session - **Hot Reload**: Add new API keys and restart in ~2-3 seconds - **Backward Compatible**: Still works with single-user mode - **Fallback Support**: GEOGUESSR_NCFA_COOKIE still works as default ## Documentation Updates - README.md: Added Multi-User Mode section with examples - README.md: Updated authentication section with multi-user details - README.md: Added "Adding New Users" workflow - Key Features section now highlights multi-user support ## Technical Details - Uses Python ContextVar for request-scoped user context - Each API key gets its own SessionManager instance - Session storage is in-memory (persists across requests, not restarts) - Default cookie (GEOGUESSR_NCFA_COOKIE) used as fallback for all users - Fully async/await compatible throughout # Pull Request ## Description <!-- Provide a clear and concise description of your changes --> ## Type of Change <!-- Mark the relevant option with an 'x' --> - [ ] Bug fix (non-breaking change which fixes an issue) - [ ] New feature (non-breaking change which adds functionality) - [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected) - [ ] Documentation update - [ ] Code refactoring - [ ] Performance improvement - [ ] Test improvement ## Related Issues <!-- Link related issues using keywords: Fixes #123, Closes #456, Related to #789 --> Fixes # ## Changes Made <!-- List the main changes in bullet points --> - - - ## Testing Performed <!-- Describe the testing you've done --> - [ ] Unit tests added/updated - [ ] Integration tests added/updated - [ ] Manual testing performed - [ ] All existing tests pass ### Test Details <!-- Provide details about how you tested your changes --> ```bash # Example test commands pytest tests/ ``` ## Screenshots (if applicable) <!-- Add screenshots to help explain your changes --> ## Checklist <!-- Ensure all items are completed before submitting --> - [ ] My code follows the project's style guidelines - [ ] I have performed a self-review of my code - [ ] I have commented my code, particularly in hard-to-understand areas - [ ] I have made corresponding changes to the documentation - [ ] My changes generate no new warnings - [ ] I have added tests that prove my fix is effective or that my feature works - [ ] New and existing unit tests pass locally with my changes - [ ] Any dependent changes have been merged and published - [ ] I have checked my code and corrected any misspellings ## Additional Context <!-- Add any other context about the pull request here --> ## Breaking Changes <!-- If this is a breaking change, describe the impact and migration path --> ## Performance Impact <!-- Describe any performance implications of your changes --> --- **By submitting this pull request, I confirm that my contribution is made under the terms of the MIT License.**
gitguardian[bot] commented 2025-11-29 23:38:31 +01:00 (Migrated from github.com)

⚠️ GitGuardian has uncovered 1 secret following the scan of your pull request.

Please consider investigating the findings and remediating the incidents. Failure to do so may lead to compromising the associated services or software components.

🔎 Detected hardcoded secret in your pull request
GitGuardian id GitGuardian status Secret Commit Filename
22991762 Triggered Generic Password 80ed791b01 src/geoguessr_mcp/auth/multi_user_session.py View secret
🛠 Guidelines to remediate hardcoded secrets
  1. Understand the implications of revoking this secret by investigating where it is used in your code.
  2. Replace and store your secret safely. Learn here the best practices.
  3. Revoke and rotate this secret.
  4. If possible, rewrite git history. Rewriting git history is not a trivial act. You might completely break other contributing developers' workflow and you risk accidentally deleting legitimate data.

To avoid such incidents in the future consider


🦉 GitGuardian detects secrets in your source code to help developers and security teams secure the modern development process. You are seeing this because you or someone else with access to this repository has authorized GitGuardian to scan your pull request.

#### ⚠️ GitGuardian has uncovered 1 secret following the scan of your pull request. Please consider investigating the findings and remediating the incidents. Failure to do so may lead to compromising the associated services or software components. <details> <summary>🔎 Detected hardcoded secret in your pull request</summary> <br> | GitGuardian id | GitGuardian status | Secret | Commit | Filename | | | -------------- | ------------------ | ------------------------------ | ---------------- | --------------- | -------------------- | | [22991762](https://dashboard.gitguardian.com/workspace/171463/incidents/22991762?occurrence=228012364) | Triggered | Generic Password | 80ed791b01ab4ef2dea57a4c4fdc18b703135f55 | src/geoguessr_mcp/auth/multi_user_session.py | [View secret](https://github.com/NyxiumYuuki/GeoGuessrMCP/commit/80ed791b01ab4ef2dea57a4c4fdc18b703135f55#diff-c297337bf08d7d09069c640339abada4660c1b03443785df3e6c664ac4abb939R76) | </details> <details> <summary>🛠 Guidelines to remediate hardcoded secrets</summary> <br> 1. Understand the implications of revoking this secret by investigating where it is used in your code. 2. Replace and store your secret safely. [Learn here](https://blog.gitguardian.com/secrets-api-management?utm_source=product&amp;utm_medium=GitHub_checks&amp;utm_campaign=check_run_comment) the best practices. 3. Revoke and [rotate this secret](https://docs.gitguardian.com/secrets-detection/secrets-detection-engine/detectors/generics/generic_password#revoke-the-secret?utm_source=product&amp;utm_medium=GitHub_checks&amp;utm_campaign=check_run_comment). 4. If possible, [rewrite git history](https://blog.gitguardian.com/rewriting-git-history-cheatsheet?utm_source=product&amp;utm_medium=GitHub_checks&amp;utm_campaign=check_run_comment). Rewriting git history is not a trivial act. You might completely break other contributing developers' workflow and you risk accidentally deleting legitimate data. To avoid such incidents in the future consider - following these [best practices](https://blog.gitguardian.com/secrets-api-management/?utm_source=product&amp;utm_medium=GitHub_checks&amp;utm_campaign=check_run_comment) for managing and storing secrets including API keys and other credentials - install [secret detection on pre-commit](https://docs.gitguardian.com/ggshield-docs/integrations/git-hooks/pre-commit?utm_source=product&amp;utm_medium=GitHub_checks&amp;utm_campaign=check_run_comment) to catch secret before it leaves your machine and ease remediation. </details> --- <sup>🦉 [GitGuardian](https://dashboard.gitguardian.com/auth/login/?utm_medium=checkruns&amp;utm_source=github&amp;utm_campaign=cr1) detects secrets in your source code to help developers and security teams secure the modern development process. You are seeing this because you or someone else with access to this repository has authorized GitGuardian to scan your pull request.<br/></sup>
Sign in to join this conversation.
No description provided.