Skip to main content

How AuthSec SDK Works

The Complete Authentication Flow

Step 1: Before Authentication - Tools Are Hidden

When your MCP server starts, users only see 5 OAuth tools:

  • oauth_start - Start authentication
  • oauth_authenticate - Complete authentication
  • oauth_status - Check auth status
  • oauth_logout - Logout
  • oauth_user_info - Get user info

All your protected business logic tools are completely hidden. Users can't even see they exist.

Step 2: User Starts Authentication

User: Call oauth_start
Server: Here's your session_id and authorization URL

The user opens the URL in their browser and authenticates with your OAuth provider (Google, GitHub, Custom Logon, etc.).

Step 3: Complete Authentication with JWT

After authentication, the user receives a JWT token containing:

{
"email": "john@company.com",
"tenant_id": "acme-corp",
"roles": ["admin", "developer"],
"groups": ["engineering"],
"scopes": ["read", "write"],
"resources": ["projects", "analytics"]
}

They call oauth_authenticate with this token.

Step 4: RBAC Magic - Validating Permissions

Here's where AuthSec SDK does the heavy lifting. For each tool in your server, it:

  1. Connects to your tenant database (tenant_acme-corp)
  2. Validates JWT claims against database:
    • Does admin role exist in roles table? ✓
    • Does write scope exist in scopes table? ✓
    • Does analytics resource exist in resources table? ✓
  3. Checks if user satisfies tool requirements
  4. Returns list of accessible tools

Step 5: Tools Are Now Visible

After authentication, users see only what they can access:

Available tools:
├── oauth_start
├── oauth_authenticate
├── oauth_status
├── calculator # ← Now visible
├── admin_dashboard # ← Now visible (has admin role)
└── view_analytics # ← Now visible (has permissions)

Step 6: Tool Execution with User Context

When a user calls a protected tool, user information is automatically injected:

@protected_by_AuthSec("admin_dashboard", roles=["admin"])
async def admin_dashboard(arguments: dict) -> list:
# User info automatically available
email = arguments['_user_info']['email'] # "john@company.com"
roles = arguments['_user_info']['roles'] # ["admin", "developer"]
tenant = arguments['_user_info']['tenant_id'] # "acme-corp"

return [{
"type": "text",
"text": f"Welcome to admin dashboard, {email}!"
}]

Architecture Overview

        ┌─────────────────────────────────┐
│ AI Assistant (Claude, etc.) │
│ MCP Client │
└────────────┬────────────────────┘
│ JSON-RPC 2.0

┌─────────────────────────────────┐
│ Your MCP Server (server.py) │
│ with AuthSec SDK │
│ │
│ OAuth Tools (always visible): │
│ ├── oauth_start │
│ ├── oauth_authenticate │
│ └── oauth_status │
│ │
│ Protected Tools (after auth): │
│ ├── @protected_by_AuthSec │
│ │ ("hello") │
│ ├── @protected_by_AuthSec │
│ │ ("admin_panel", │
│ │ roles=["admin"]) │
│ └── ... │
└────────────┬────────────────────┘
│ HTTPS

┌─────────────────────────────────┐
│ AuthSec SDK Manager Service │
│ (Managed by AuthSec) │
│ │
│ ├── OAuth flow management │
│ ├── JWT validation │
│ ├── RBAC checking │
│ ├── Session management │
│ └── Vault integration │
└────────────┬────────────────────┘


┌─────────────────────────────────┐
│ External Services │
│ ├── OAuth Provider │
│ ├── HashiCorp Vault │
│ └── Tenant Database │
└─────────────────────────────────┘

Multi-Tenant Architecture

  • Master Database: Tenant mappings
  • Tenant Databases: Each tenant has isolated database (tenant_{tenant_id})
    • RBAC tables (roles, scopes, resources, permissions)
    • Authenticated sessions
    • Service configurations
    • User data