Skip to content
Back to skills

1751 Registry Auth Architecture D441f63f

ASecurity

This document provides comprehensive technical documentation for the MCP Gateway Registry's authentication and authorization system. While the main [auth.md](./auth.md) covers the overall system architecture, this document focuses specifically on the **registry application's internal authentication mechanisms**, UI-based authentication flows, and technical implementation details.

  • 9 stars
  • 0 votes
  • 0 copies
  • 0 views
  • Added June 1, 2026
developmentjavascriptpythongojavabashfastapidebuggingapidatabasesecurity

Works with

  • cli
  • api
  • mcp

Security analysis

A92/100
  • mediumUses curl or wget to download content

Pro scans all 2 files and shows the line behind each finding

Scanned June 1, 2026

npx -y skills add tools-only/X-Skills --skill 1751-registry-auth-architecture_d441f63f --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of 1751 Registry Auth Architecture D441f63f?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for 1751 Registry Auth Architecture D441f63f
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/tools-only-1751-registry-auth-architecture-d441f63f/badge)](https://www.skillsdirectory.com/skills/tools-only-1751-registry-auth-architecture-d441f63f)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
# Registry Authentication Architecture

This document provides comprehensive technical documentation for the MCP Gateway Registry's authentication and authorization system. While the main [auth.md](./auth.md) covers the overall system architecture, this document focuses specifically on the **registry application's internal authentication mechanisms**, UI-based authentication flows, and technical implementation details.

## Table of Contents

1. [Overview](#overview)
2. [Authentication Architecture](#authentication-architecture)
3. [UI Authentication System](#ui-authentication-system)
4. [Authorization & Permissions](#authorization--permissions)
5. [Technical Implementation](#technical-implementation)
6. [Configuration](#configuration)
7. [Troubleshooting](#troubleshooting)

## Overview

The MCP Gateway Registry implements a sophisticated dual-authentication system that supports:

- **Traditional username/password authentication** for local development and basic setups
- **OAuth2/SAML integration** with enterprise identity providers (Cognito, etc.)
- **Session-based authentication** using secure HTTP cookies
- **Role-based access control** with groups and scopes
- **Fine-grained permissions** for server management operations

### Key Features

- 🔐 **Dual Authentication Methods**: Traditional + OAuth2
- 🎯 **Role-Based Access Control**: Admin, User, and custom roles
- 🏢 **Enterprise Integration**: Cognito, SAML, and other IdPs
- 🔒 **Secure Session Management**: Encrypted cookies with expiration
- 🎛️ **Permission-Based UI**: Dynamic UI based on user permissions
- 📊 **Audit Trail**: Comprehensive logging of authentication events

## Authentication Architecture

### High-Level Component Overview

```mermaid
graph TB
    subgraph "Browser"
        UI[Registry Web UI]
        LoginForm[Login Form]
    end
    
    subgraph "Registry Application"
        AuthRoutes[Auth Routes<br/>registry/auth/routes.py]
        AuthDeps[Auth Dependencies<br/>registry/auth/dependencies.py]
        ServerRoutes[Protected API Routes<br/>registry/api/server_routes.py]
        Templates[Jinja2 Templates]
    end
    
    subgraph "Session Management"
        Cookies[HTTP Cookies<br/>mcp_gateway_session]
        SessionSigner[URLSafeTimedSerializer]
        Sessions[Session Data Store]
    end
    
    subgraph "External Systems"
        AuthServer[Auth Server<br/>:8888]
        Cognito[Amazon Cognito]
        LocalAuth[Local User DB]
    end
    
    UI --> AuthRoutes
    LoginForm --> AuthRoutes
    AuthRoutes --> AuthDeps
    AuthRoutes --> Templates
    ServerRoutes --> AuthDeps
    AuthDeps --> Cookies
    Cookies --> SessionSigner
    SessionSigner --> Sessions
    
    AuthRoutes -.-> AuthServer
    AuthServer -.-> Cognito
    AuthRoutes -.-> LocalAuth
    
    classDef browser fill:#e3f2fd,stroke:#1976d2
    classDef registry fill:#f3e5f5,stroke:#7b1fa2
    classDef session fill:#fff3e0,stroke:#f57c00
    classDef external fill:#e8f5e8,stroke:#388e3c
    
    class UI,LoginForm browser
    class AuthRoutes,AuthDeps,ServerRoutes,Templates registry
    class Cookies,SessionSigner,Sessions session
    class AuthServer,Cognito,LocalAuth external
```

### Authentication Flow Architecture

```mermaid
sequenceDiagram
    participant U as User/Browser
    participant R as Registry App
    participant AS as Auth Server
    participant IdP as Identity Provider
    
    Note over U,IdP: 1. Initial Access (Unauthenticated)
    U->>R: GET / (no session cookie)
    R->>R: Check session cookie
    R->>U: 302 Redirect to /login
    
    Note over U,IdP: 2. Authentication Method Selection
    U->>R: GET /login
    R->>AS: GET /oauth2/providers
    AS->>R: Available OAuth2 providers
    R->>U: Login form with OAuth options
    
    Note over U,IdP: 3a. Traditional Authentication
    alt Traditional Login
        U->>R: POST /login (username/password)
        R->>R: validate_login_credentials()
        R->>R: create_session_cookie()
        R->>U: Set mcp_gateway_session cookie + redirect
    
    Note over U,IdP: 3b. OAuth2 Authentication
    else OAuth2 Login
        U->>R: GET /auth/{provider}
        R->>U: 302 Redirect to Auth Server
        U->>AS: OAuth2 flow initiation
        AS->>IdP: OAuth2 PKCE flow
        IdP->>AS: Auth code + user info
        AS->>AS: Map groups to scopes
        AS->>AS: Create session cookie
        AS->>U: Set mcp_gateway_session cookie
        U->>R: GET /auth/callback
        R->>R: Validate session cookie
        R->>U: 302 Redirect to /
    end
    
    Note over U,IdP: 4. Authenticated Access
    U->>R: GET / (with session cookie)
    R->>R: enhanced_auth() dependency
    R->>R: Decode & validate session
    R->>R: Load user permissions
    R->>U: Filtered dashboard based on permissions
```

## UI Authentication System

### Login Interface Components

The registry provides a modern, responsive login interface that dynamically adapts based on available authentication providers.

#### Login Form Structure

```mermaid
graph LR
    subgraph "Login Page (/login)"
        LoginHeader[Header with Logo]
        ErrorDisplay[Error Message Display]
        
        subgraph "Authentication Options"
            TraditionalForm[Traditional Login Form]
            OAuth2Section[OAuth2 Provider Buttons]
        end
        
        subgraph "Traditional Form"
            UsernameField[Username Input]
            PasswordField[Password Input]
            LoginButton[Login Button]
        end
        
        subgraph "OAuth2 Providers"
            CognitoBtn[Amazon Cognito Button]
            SAMLBtn[SAML Provider Button]
            CustomBtn[Custom Provider Button]
        end
    end
    
    LoginHeader --> ErrorDisplay
    ErrorDisplay --> TraditionalForm
    ErrorDisplay --> OAuth2Section
    TraditionalForm --> UsernameField
    TraditionalForm --> PasswordField
    TraditionalForm --> LoginButton
    OAuth2Section --> CognitoBtn
    OAuth2Section --> SAMLBtn
    OAuth2Section --> CustomBtn
    
    classDef form fill:#e3f2fd,stroke:#1976d2
    classDef oauth fill:#fff3e0,stroke:#f57c00
    classDef input fill:#f3e5f5,stroke:#7b1fa2
    
    class TraditionalForm,UsernameField,PasswordField,LoginButton form
    class OAuth2Section,CognitoBtn,SAMLBtn,CustomBtn oauth
    class LoginHeader,ErrorDisplay input
```

#### Dynamic Provider Loading

The login form dynamically loads available OAuth2 providers:

```python
# registry/auth/routes.py
async def get_oauth2_providers():
    """Fetch available OAuth2 providers from auth server"""
    try:
        async with httpx.AsyncClient() as client:
            response = await client.get(f"{settings.auth_server_url}/oauth2/providers")
            if response.status_code == 200:
                return response.json().get("providers", [])
    except Exception as e:
        logger.warning(f"Failed to fetch OAuth2 providers: {e}")
    return []

@router.get("/login", response_class=HTMLResponse)
async def login_form(request: Request, error: str | None = None):
    oauth_providers = await get_oauth2_providers()
    return templates.TemplateResponse("login.html", {
        "request": request, 
        "error": error,
        "oauth_providers": oauth_providers
    })
```

### Dashboard UI with Permission-Based Access

The main dashboard dynamically renders content based on user permissions:

```mermaid
graph TB
    subgraph "Dashboard Components"
        Header[Header with User Info]
        Sidebar[Navigation Sidebar]
        MainContent[Main Content Area]
        
        subgraph "Header Elements"
            Logo[Registry Logo]
            UserDisplay[Username Display]
            LogoutBtn[Logout Button]
        end
        
        subgraph "Sidebar Elements"
            AllServers[All Servers Link]
            UserServers[Accessible Servers]
            AdminTools[Admin Tools]
            HealthStatus[Health Status]
        end
        
        subgraph "Main Content"
            ServiceCards[Service Cards Grid]
            SearchBar[Search & Filters]
            ToggleControls[Enable/Disable Toggles]
            EditButtons[Edit Server Buttons]
        end
    end
    
    Header --> Sidebar
    Sidebar --> MainContent
    Header --> Logo
    Header --> UserDisplay  
    Header --> LogoutBtn
    Sidebar --> AllServers
    Sidebar --> UserServers
    Sidebar --> AdminTools
    Sidebar --> HealthStatus
    MainContent --> ServiceCards
    MainContent --> SearchBar
    MainContent --> ToggleControls
    MainContent --> EditButtons
    
    classDef header fill:#e8eaf6,stroke:#3f51b5
    classDef sidebar fill:#e0f2f1,stroke:#4caf50
    classDef content fill:#fff3e0,stroke:#ff9800
    classDef controls fill:#fce4ec,stroke:#e91e63
    
    class Header,Logo,UserDisplay,LogoutBtn header
    class Sidebar,AllServers,UserServers,AdminTools,HealthStatus sidebar
    class MainContent,ServiceCards,SearchBar content
    class ToggleControls,EditButtons controls
```

#### Permission-Based UI Rendering

The UI dynamically shows/hides elements based on user permissions:

```html
<!-- registry/templates/index.html -->
<div class="header-right">
    <div class="user-display">
        <span>{{ username }}</span>
        {% if user_context.is_admin %}
            <span class="admin-badge">Admin</span>
        {% endif %}
    </div>
    <form method="post" action="/logout" class="logout-form">
        <button type="submit" class="logout-button">Logout</button>
    </form>
</div>

<!-- Service management controls -->
{% for service in services %}
<div class="service-card">
    <div class="card-header">
        <h2>{{ service.display_name }}</h2>
        {% if user_context.can_modify_servers %}
            <div class="header-right-items">
                <a href="/edit/{{ service.path[1:] }}" class="edit-button">Edit</a>
            </div>
        {% endif %}
    </div>
    
    <div class="card-footer">
        {% if user_context.can_modify_servers %}
            <!-- Toggle switch for admins/editors -->
            <form method="post" action="/toggle/{{ service.path[1:] }}" class="toggle-form">
                <label class="switch">
                    <input type="checkbox" name="enabled" 
                           {% if service.is_enabled %}checked{% endif %}>
                    <span class="slider round"></span>
                </label>
            </form>
        {% else %}
            <!-- Read-only status for regular users -->
            <div class="read-only-status">
                <span class="status-text">
                    {% if service.is_enabled %}Enabled{% else %}Disabled{% endif %}
                </span>
            </div>
        {% endif %}
    </div>
</div>
{% endfor %}
```

### WebSocket Integration for Real-Time Updates

The UI includes real-time health status updates via WebSocket:

```javascript
// Health status WebSocket connection
const ws = new WebSocket('ws://localhost:7860/ws/health_status');

ws.onmessage = function(event) {
    const healthData = JSON.parse(event.data);
    updateHealthStatusUI(healthData);
};

function updateHealthStatusUI(healthData) {
    for (const [servicePath, status] of Object.entries(healthData)) {
        const card = document.querySelector(`[data-service-path="${servicePath}"]`);
        if (card) {
            const statusElement = card.querySelector('.health-status');
            statusElement.textContent = status.status;
            statusElement.className = `health-status ${status.status}`;
            
            const toolCount = card.querySelector('.tool-count');
            toolCount.textContent = `${status.num_tools} tools`;
        }
    }
}
```

## Authorization & Permissions

### Permission Model Overview

The registry implements a sophisticated role-based access control (RBAC) system:

```mermaid
graph TB
    subgraph "User Identity"
        User[User Account]
        Groups[User Groups]
        AuthMethod[Auth Method]
    end
    
    subgraph "Permission Mapping"
        Scopes[MCP Scopes]
        GroupMapping[Group → Scope Mapping]
        ServerAccess[Server Access List]
    end
    
    subgraph "Capabilities"
        ReadAccess[Read Access]
        ModifyAccess[Modify Access]
        AdminAccess[Admin Access]
        ServerSpecific[Server-Specific Access]
    end
    
    User --> Groups
    User --> AuthMethod
    Groups --> GroupMapping
    GroupMapping --> Scopes
    Scopes --> ServerAccess
    
    ServerAccess --> ReadAccess
    ServerAccess --> ModifyAccess
    ServerAccess --> AdminAccess
    ServerAccess --> ServerSpecific
    
    classDef identity fill:#e3f2fd,stroke:#1976d2
    classDef mapping fill:#f3e5f5,stroke:#7b1fa2
    classDef capability fill:#e8f5e8,stroke:#388e3c
    
    class User,Groups,AuthMethod identity
    class Scopes,GroupMapping,ServerAccess mapping
    class ReadAccess,ModifyAccess,AdminAccess,ServerSpecific capability
```

### Role Definitions

#### 1. Admin Role (`mcp-admin` group)
- **Full system access**: Can view, modify, create, and delete all servers
- **User management**: Can view all user sessions and permissions
- **System configuration**: Can modify global settings
- **Unrestricted scopes**: `mcp-servers-unrestricted/read`, `mcp-servers-unrestricted/execute`

#### 2. User Role (`mcp-user` group)
- **Read-only access**: Can view servers and tools they have permission for
- **No modification rights**: Cannot toggle servers or edit configurations
- **Filtered view**: Only sees servers they have explicit access to
- **Restricted scopes**: Based on group mappings

#### 3. Server-Specific Roles (`mcp-server-{name}` groups)
- **Targeted access**: Access to specific servers based on group name
- **Execute permissions**: Can use tools from assigned servers
- **Limited modification**: May have toggle permissions for specific servers

### Scope Configuration System

The system uses a YAML-based scope configuration (`auth_server/scopes.yml`):

```yaml
# Example scope configuration
group_mappings:
  mcp-admin:
    - "mcp-servers-unrestricted/read"
    - "mcp-servers-unrestricted/execute"
  
  mcp-user:
    - "mcp-servers-restricted/read"
  
  mcp-server-fininfo:
    - "mcp-servers-fininfo/read"
    - "mcp-servers-fininfo/execute"

# Scope definitions
mcp-servers-fininfo/read:
  - server: "Financial Info Proxy"
    permissions: ["read"]

mcp-servers-fininfo/execute:
  - server: "Financial Info Proxy"
    permissions: ["read", "execute"]
```

### Permission Checking Logic

```python
# registry/auth/dependencies.py
def enhanced_auth(session: str = None) -> Dict[str, Any]:
    """Enhanced authentication with full user context"""
    session_data = get_user_session_data(session)
    
    username = session_data['username']
    groups = session_data.get('groups', [])
    auth_method = session_data.get('auth_method', 'traditional')
    
    # Map groups to scopes
    if auth_method == 'oauth2':
        scopes = map_cognito_groups_to_scopes(groups)
    else:
        # Traditional users get admin scopes
        scopes = ['mcp-servers-unrestricted/read', 'mcp-servers-unrestricted/execute']
        if not groups:
            groups = ['mcp-admin']
    
    # Calculate permissions
    accessible_servers = get_user_accessible_servers(scopes)
    can_modify = user_can_modify_servers(groups, scopes)
    is_admin = 'mcp-admin' in groups
    
    return {
        'username': username,
        'groups': groups,
        'scopes': scopes,
        'auth_method': auth_method,
        'accessible_servers': accessible_servers,
        'can_modify_servers': can_modify,
        'is_admin': is_admin
    }
```

### Server Access Filtering

```python
# registry/services/server_service.py
def get_all_servers_with_permissions(self, accessible_servers: Optional[List[str]] = None) -> Dict[str, Dict[str, Any]]:
    """Get servers filtered by user permissions"""
    all_servers = self.get_all_servers()
    
    if accessible_servers is None:
        return all_servers  # Admin access
    
    filtered_servers = {}
    for path, server_info in all_servers.items():
        server_name = server_info.get("server_name", "")
        if server_name in accessible_servers:
            filtered_servers[path] = server_info
    
    return filtered_servers
```

## Technical Implementation

### Session Management Deep Dive

#### Session Cookie Structure

The registry uses `itsdangerous.URLSafeTimedSerializer` for secure session management:

```python
# registry/auth/dependencies.py
from itsdangerous import URLSafeTimedSerializer

signer = URLSafeTimedSerializer(settings.secret_key)

def create_session_cookie(username: str, auth_method: str = "traditional", 
                         provider: str = "local") -> str:
    """Create a session cookie for a user"""
    session_data = {
        "username": username,
        "auth_method": auth_method,
        "provider": provider,
        "created_at": datetime.utcnow().isoformat(),
        "groups": [],  # Populated during OAuth2 flow
        "scopes": []   # Calculated from groups
    }
    return signer.dumps(session_data)
```

#### Session Validation Flow

```mermaid
sequenceDiagram
    participant R as Request
    participant D as Auth Dependency
    participant S as Session Signer
    participant C as Config/Scopes
    
    R->>D: Request with session cookie
    D->>S: Validate cookie signature
    
    alt Valid Cookie
        S->>D: Decoded session data
        D->>D: Check expiration
        D->>C: Load scope mappings
        D->>D: Calculate permissions
        D->>R: User context object
    else Invalid/Expired Cookie
        S->>D: SignatureExpired/BadSignature
        D->>R: HTTP 401 Unauthorized
    end
```

### Authentication Dependencies Architecture

The registry uses FastAPI's dependency injection for authentication:

```python
# registry/auth/dependencies.py

def get_current_user(session: str = Cookie(alias="mcp_gateway_session")) -> str:
    """Basic authentication - returns username only"""
    # Used for simple authentication checks
    
def get_user_session_data(session: str = Cookie(alias="mcp_gateway_session")) -> Dict[str, Any]:
    """Full session data extraction"""
    # Used when you need complete session information
    
def enhanced_auth(session: str = Cookie(alias="mcp_gateway_session")) -> Dict[str, Any]:
    """Enhanced authentication with permissions and context"""
    # Used for permission-based access control
```

### Route Protection Patterns

```python
# registry/api/server_routes.py

@router.get("/", response_class=HTMLResponse)
async def read_root(request: Request, 
                   user_context: Annotated[dict, Depends(enhanced_auth)]):
    """Main dashboard with permission-based filtering"""
    if user_context['is_admin']:
        all_servers = server_service.get_all_servers()
    else:
        all_servers = server_service.get_all_servers_with_permissions(
            user_context['accessible_servers']
        )
    # Render dashboard...

@router.post("/toggle/{service_path:path}")
async def toggle_service_route(service_path: str,
                              user_context: Annotated[dict, Depends(enhanced_auth)]):
    """Service toggle with permission checking"""
    if not user_context['can_modify_servers']:
        raise HTTPException(status_code=403, 
                          detail="You do not have permission to modify servers")
    
    if not user_context['is_admin']:
        if not server_service.user_can_access_server_path(
            service_path, user_context['accessible_servers']):
            raise HTTPException(status_code=403,
                              detail="You do not have access to this server")
    # Perform toggle...
```

### OAuth2 Integration Architecture

```mermaid
graph LR
    subgraph "Registry Components"
        AuthRoutes[Auth Routes]
        AuthDeps[Auth Dependencies]
        Config[Configuration]
    end
    
    subgraph "External Auth Server"
        OAuth2Handler[OAuth2 Handler]
        ProviderManager[Provider Manager]
        TokenValidator[Token Validator]
    end
    
    subgraph "Identity Providers"
        Cognito[Amazon Cognito]
        SAML[SAML Provider]
        Custom[Custom OAuth2]
    end
    
    AuthRoutes --> OAuth2Handler
    AuthDeps --> Config
    OAuth2Handler --> ProviderManager
    ProviderManager --> Cognito
    ProviderManager --> SAML
    ProviderManager --> Custom
    TokenValidator --> Cognito
    
    classDef registry fill:#e3f2fd,stroke:#1976d2
    classDef auth fill:#f3e5f5,stroke:#7b1fa2
    classDef provider fill:#e8f5e8,stroke:#388e3c
    
    class AuthRoutes,AuthDeps,Config registry
    class OAuth2Handler,ProviderManager,TokenValidator auth
    class Cognito,SAML,Custom provider
```

### WebSocket Authentication

The registry includes real-time features via WebSocket with authentication:

```python
# registry/health/routes.py
@router.websocket("/ws/health_status")
async def websocket_endpoint(websocket: WebSocket):
    """WebSocket endpoint with authentication"""
    # WebSocket authentication is handled differently
    # since cookies are automatically included in WebSocket handshake
    try:
        await health_service.add_websocket_connection(websocket)
        while True:
            await websocket.receive_text()  # Keep alive
    except WebSocketDisconnect:
        await health_service.remove_websocket_connection(websocket)
```

## Configuration

### Environment Variables

The registry authentication system requires several configuration parameters:

```bash
# Core authentication settings
SECRET_KEY=your-secure-secret-key-here
SESSION_COOKIE_NAME=mcp_gateway_session
SESSION_MAX_AGE_SECONDS=28800  # 8 hours

# Traditional authentication
ADMIN_USER=admin
ADMIN_PASSWORD=secure-password

# OAuth2/External auth server integration
AUTH_SERVER_URL=http://localhost:8888
AUTH_SERVER_EXTERNAL_URL=http://localhost:8888

# Database/storage paths (auto-configured for container vs local dev)
CONTAINER_APP_DIR=/app
CONTAINER_REGISTRY_DIR=/app/registry
CONTAINER_LOG_DIR=/app/logs
```

### Development vs Production Configuration

#### Local Development (`settings.is_local_dev = True`)
```python
# registry/core/config.py
@property
def is_local_dev(self) -> bool:
    return not Path("/app").exists()

@property
def templates_dir(self) -> Path:
    if self.is_local_dev:
        return Path.cwd() / "registry" / "templates"
    return self.container_registry_dir / "templates"
```

#### Container/Production (`settings.is_local_dev = False`)
- Paths point to `/app/registry/` structure
- Optimized logging and security settings
- External auth server integration

### Authentication Provider Configuration

#### Traditional Authentication
```python
# registry/auth/dependencies.py
def validate_login_credentials(username: str, password: str) -> bool:
    """Validate traditional login credentials"""
    return username == settings.admin_user and password == settings.admin_password
```

#### OAuth2 Provider Setup
```python
# External auth server integration
async def get_oauth2_providers():
    """Fetch available OAuth2 providers from auth server"""
    try:
        response = await client.get(f"{settings.auth_server_url}/oauth2/providers")
        return response.json().get("providers", [])
    except Exception:
        return []  # Fallback to traditional auth only
```

## Troubleshooting

### Common Authentication Issues

#### 1. Session Cookie Problems

**Issue**: User gets redirected to login page repeatedly
```python
# Debug session cookie validation
try:
    data = signer.loads(session, max_age=settings.session_max_age_seconds)
    logger.info(f"Session data: {data}")
except SignatureExpired:
    logger.warning("Session expired")
except BadSignature:
    logger.warning("Invalid session signature")
```

**Solutions**:
- Check `SECRET_KEY` consistency across restarts
- Verify cookie expiration settings
- Ensure browser accepts cookies from the domain

#### 2. OAuth2 Integration Issues

**Issue**: OAuth2 login fails or redirects incorrectly
```python
# Debug OAuth2 callback
@router.get("/auth/callback")
async def oauth2_callback(request: Request, error: str = None):
    if error:
        logger.error(f"OAuth2 error: {error}")
        return RedirectResponse(url=f"/login?error={error}")
    
    # Check session cookie validity
    session_cookie = request.cookies.get(settings.session_cookie_name)
    logger.info(f"OAuth2 callback session: {session_cookie[:20]}..." if session_cookie else "No session")
```

**Solutions**:
- Verify `AUTH_SERVER_URL` and `AUTH_SERVER_EXTERNAL_URL` settings
- Check auth server connectivity: `curl http://localhost:8888/oauth2/providers`
- Ensure redirect URIs match in OAuth2 provider configuration

#### 3. Permission Issues

**Issue**: Users can't access servers they should have permission for
```python
# Debug permission calculation
def debug_user_permissions(user_context: dict):
    logger.info(f"User: {user_context['username']}")
    logger.info(f"Groups: {user_context['groups']}")
    logger.info(f"Scopes: {user_context['scopes']}")
    logger.info(f"Accessible servers: {user_context['accessible_servers']}")
    logger.info(f"Can modify: {user_context['can_modify_servers']}")
```

**Solutions**:
- Verify group mappings in `auth_server/scopes.yml`
- Check user group assignments in identity provider
- Ensure scope configuration matches server names exactly

#### 4. WebSocket Authentication Issues

**Issue**: Real-time updates not working
```python
# Debug WebSocket connections
@router.websocket("/ws/health_status")
async def websocket_endpoint(websocket: WebSocket):
    logger.info(f"WebSocket connection from: {websocket.client}")
    try:
        await websocket.accept()
        logger.info("WebSocket connection accepted")
    except Exception as e:
        logger.error(f"WebSocket error: {e}")
```

**Solutions**:
- Check browser console for WebSocket errors
- Verify WebSocket URL scheme (ws:// vs wss://)
- Ensure firewall/proxy allows WebSocket connections

### Logging and Debugging

#### Enable Debug Logging
```python
# registry/main.py
logging.basicConfig(level=logging.DEBUG)
logger = logging.getLogger(__name__)
```

#### Authentication Event Logging
```python
# Custom auth logging
def log_auth_event(event_type: str, username: str = None, details: dict = None):
    logger.info(f"AUTH_EVENT: {event_type}", extra={
        'username': username,
        'event_type': event_type,
        'details': details,
        'timestamp': datetime.utcnow().isoformat()
    })

# Usage examples
log_auth_event('LOGIN_SUCCESS', username='admin')
log_auth_event('PERMISSION_DENIED', username='user', details={'resource': '/toggle/fininfo'})
log_auth_event('SESSION_EXPIRED', username='user')
```

#### Health Check for Auth Components
```python
@app.get("/health/auth")
async def auth_health_check():
    """Health check for authentication components"""
    health_status = {
        "session_signer": "ok",
        "auth_server": "unknown",
        "oauth2_providers": []
    }
    
    # Test auth server connectivity
    try:
        async with httpx.AsyncClient(timeout=5.0) as client:
            response = await client.get(f"{settings.auth_server_url}/health")
            if response.status_code == 200:
                health_status["auth_server"] = "ok"
                
                # Test OAuth2 providers
                providers_response = await client.get(f"{settings.auth_server_url}/oauth2/providers")
                if providers_response.status_code == 200:
                    health_status["oauth2_providers"] = providers_response.json().get("providers", [])
    except Exception as e:
        health_status["auth_server"] = f"error: {e}"
    
    return health_status
```

This comprehensive authentication architecture ensures secure, scalable, and maintainable access control for the MCP Gateway Registry while providing flexibility for both local development and enterprise deployments. 

Files in this skill

  • README.md937 B
  • skill.md27.3 KB

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.