Skip to content

[AUTH FEATURE]: Authentication & Authorization - SSO + Identity-Provider Integration #220

@kumar-tiger

Description

@kumar-tiger

Authentication & Authorization - SSO + Identity-Provider Integration

🧭 Epic

Title: Add SSO & IdP-Issued Tokens to Gateway
Goal: Replace hard-coded credentials with full SSO login (SAML/OIDC) for the web UI and bearer-token introspection for the API, so every request carries a verified user identity & scopes.
Why now: We run several gateways scoped to different teams; central auth will slash onboarding time and guarantee users only hit tools & servers they're entitled to.

Standards:


🧭 Type of Feature

  • Security hardening
  • New functionality (experimental)

🙋‍♂️ User Story 1 - Browser SSO Flow

As a: Platform engineer
I want: the UI to redirect unauthenticated users to our corporate IdP and honor SAML/OIDC assertions
So that: users log in once and land back on the dashboard already mapped to their roles.

✅ Acceptance Criteria

Scenario: Successful SSO login
Given an unauthenticated browser visits "/"
When the gateway redirects to the IdP login page
And the user completes the IdP challenge
Then the gateway MUST create an encrypted session cookie
And MUST attach the user's uid & groups to subsequent requests

🙋‍♂️ User Story 2 - API Token Introspection

As a: Tool developer
I want: the REST/MCP API to accept only IdP-issued JWTs or opaque reference tokens
So that: every call is cryptographically bound to a user & scopes (least privilege).

✅ Acceptance Criteria

Scenario: Reject expired or tampered tokens
Given a client sends "Authorization: Bearer <token>"
When the token fails signature or expiry checks
Then respond 401 "invalid_token"
And no business logic executes

🙋‍♂️ User Story 3 - Role-Based Access Control (RBAC)

As a: Security admin
I want: gateway routes & tool invocations guarded by group/role policies
So that: "finance-analyst" users cannot hit "devops.*" tools.

✅ Acceptance Criteria

Scenario: Enforce RBAC on tool call
Given user belongs to groups ["finance-analyst"]
And attempts to invoke "devops.kubectl"
Then respond 403 "forbidden_scope"

📐 Design Sketch

flowchart TD
    Browser -->|SAML/OIDC| IdP[(Corporate IdP)]
    IdP --> GW[Gateway Auth Service]
    subgraph Gateway
        GW --> AC[Access Checker]
        AC --> API["UI / JSON-RPC / REST"]
    end
Loading
Component Change Detail
auth_service.py NEW SAML/OIDC callback handling, token validator
Middleware UPDATE Authorization: bearer token extraction & cache
DB NEW users, groups, sessions tables
Config ADD OIDC_* / SAML_* settings
sequenceDiagram
    participant B as Browser/User-Agent
    participant C as MCP Client
    participant AS as Authorization Server
    participant RS as MCP Resource Server

    Note over C,RS: 🔍 Phase 1: Discovery & Initial Request
    C->>RS: MCP request without token
    RS->>C: HTTP 401 Unauthorized\nWWW-Authenticate: Bearer realm="MCP",\nresource_metadata="https://mcp.example.com/.well-known/oauth-protected-resource"

    Note over C,AS: 🔍 Phase 2: Authorization Server Discovery
    C->>RS: GET /.well-known/oauth-protected-resource
    RS->>C: Protected Resource Metadata\n{authorization_servers: ["https://auth.example.com"]}

    C->>AS: GET /.well-known/oauth-authorization-server
    AS->>C: Authorization Server Metadata\n{authorization_endpoint, token_endpoint,\nregistration_endpoint, pkce_required: true}

    Note over C,AS: 🔧 Phase 3: Dynamic Client Registration (RFC 7591)
    alt Dynamic Client Registration Supported
        C->>AS: POST /register\n{client_name: "MCP Client",\ngrant_types: ["authorization_code"],\nresponse_types: ["code"],\nredirect_uris: ["http://localhost:8080/callback"]}
        AS->>C: Client Credentials\n{client_id: "abc123", client_secret: "xyz789"}
    else Pre-registered Client
        Note over C: Use hardcoded client_id
    end

    Note over C,B: 🔐 Phase 4: Authorization Request with PKCE & Resource Parameter
    C->>C: Generate PKCE parameters\ncode_verifier = random_string(43-128)\ncode_challenge = SHA256(code_verifier)\ncode_challenge_method = "S256"

    C->>B: Redirect to Authorization URL\nhttps://auth.example.com/authorize?\nresponse_type=code&\nclient_id=abc123&\nredirect_uri=http://localhost:8080/callback&\nscope=mcp:read mcp:write&\nstate=random_state&\ncode_challenge=xyz&\ncode_challenge_method=S256&\nresource=https://mcp.example.com

    Note over B,AS: 🔐 Phase 5: User Authorization
    B->>AS: Authorization request with all parameters
    AS->>AS: Validate client_id, redirect_uri,\nresource parameter, PKCE challenge
    AS->>B: Show consent screen\n"MCP Client wants to access\nhttps://mcp.example.com on your behalf"
    B->>AS: User authorizes access

    Note over AS,C: 🎫 Phase 6: Authorization Code Exchange
    AS->>B: Redirect to callback\nhttp://localhost:8080/callback?\ncode=auth_code_123&state=random_state
    B->>C: Authorization code callback
    C->>C: Verify state parameter matches

    C->>AS: POST /token\n{grant_type: "authorization_code",\ncode: "auth_code_123",\nredirect_uri: "http://localhost:8080/callback",\nclient_id: "abc123",\nclient_secret: "xyz789",\ncode_verifier: "original_verifier",\nresource: "https://mcp.example.com"}

    AS->>AS: Validate:\n• Authorization code\n• PKCE code_verifier\n• Resource parameter\n• Client credentials

    AS->>C: Access Token Response\n{access_token: "eyJ...",\ntoken_type: "Bearer",\nexpires_in: 3600,\nrefresh_token: "refresh_123",\nscope: "mcp:read mcp:write",\naud: "https://mcp.example.com"}

    Note over C,RS: 🚀 Phase 7: Authenticated MCP Communication
    C->>RS: MCP request\nAuthorization: Bearer eyJ...\nContent-Type: application/json\n{jsonrpc: "2.0", method: "list_tools"}

    RS->>RS: Validate token:\n• Signature verification\n• Expiry check\n• Audience validation (aud: mcp.example.com)\n• Scope verification

    RS->>C: MCP response\n{jsonrpc: "2.0", result: {tools: [...]}}

    Note over C,RS: 🔄 Phase 8: Token Refresh (when needed)
    alt Token Expired
        C->>AS: POST /token\n{grant_type: "refresh_token",\nrefresh_token: "refresh_123",\nclient_id: "abc123",\nclient_secret: "xyz789",\nresource: "https://mcp.example.com"}
        AS->>C: New Access Token\n{access_token: "new_eyJ...",\nrefresh_token: "new_refresh_456"}
    end
Loading

🔄 Roll-out Plan

  1. Phase 0: Feature-flag EXPERIMENTAL_SSO off by default.
  2. Phase 1: Shadow-mode (accept either legacy creds or SSO) in staging.
  3. Phase 2: Enforce SSO only; auto-migrate active sessions.
  4. Phase 3: Remove legacy credential endpoints & rotate secrets.

📝 Spec-Draft Clauses

  1. Auth Clause - "Gateways MUST authenticate requests via IdP tokens or mutual TLS."
  2. RBAC Clause - "Servers SHOULD map IdP ‘groups' claims to tool/route policies."

📣 Next Steps

  • Spike OIDC library integration with GitHub sandbox.
  • Draft database schema migration.
  • Open follow-up PR to wire RBAC middleware.

Sub-issues

Metadata

Metadata

Assignees

Labels

enhancementNew feature or requestpythonPython / backend development (FastAPI)securityImproves securitytriageIssues / Features awaiting triage

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions