{"slug":"developers/DESCOPE_CONNECTION_HUB_REFINED","title":"Descope Connection Hub Architecture (Refined v1.1)","section":"developers","sectionLabel":"Developers","status":"unclassified","type":"document","path":"developers/DESCOPE_CONNECTION_HUB_REFINED.mdx","bytes":11812,"description":null,"updated":null,"source":"integratewise/Integratewise-docs-wiki","content":"\n> **Status: SUPERSEDED AUTH SNAPSHOT.** Descope is not the canonical user or\n> workspace identity root. Clerk identity is verified at Gateway; connector\n> authorization follows the current provider-management/connection contract.\n> See\n> [`docs/architecture/IMPLEMENTATION_CONTRACT_v1.1.md`](docs/architecture/IMPLEMENTATION_CONTRACT_v1.1.md).\n\n**Original Status**: CANONICAL — supersedes DESCOPE_CONNECTION_HUB.md and DESCOPE_ARCHITECTURE_SUMMARY.md\n**Date**: July 17, 2026  \n**Version**: v1.1 (Provider-Abstracted with Refined Ownership)  \n**Canonical Path**: docs/architecture/CONNECTION_ARCHITECTURE.md\n\n---\n\n## Canonical Ownership Model\n\nClear separation of concerns:\n\n| Layer                    | Owner             | Responsibility                        |\n| ------------------------ | ----------------- | ------------------------------------- |\n| User authentication      | Descope           | Login, SSO, MFA, session management   |\n| OAuth authorization      | Descope           | User consent, authorization flow      |\n| Access tokens            | Descope           | Token generation, signing, validation |\n| Refresh tokens           | Descope           | Token refresh, rotation, expiry       |\n| Credential refresh       | Descope           | Auto-refresh expired credentials      |\n| Authorization references | Descope           | `descope:github:auth_123` generation  |\n| **Connection metadata**  | **IntegrateWise** | Status, labels, policies, last used   |\n| **Continuity**           | **IntegrateWise** | Memory, audit trail, context          |\n| **Capability routing**   | **MCP Pool**      | Route selection, provider dispatch    |\n| **Governance**           | **IntegrateWise** | Authority checks, approval workflows  |\n| **Memory / Spine**       | **IntegrateWise** | Persistent state, knowledge base      |\n\n---\n\n## What Lives in the Spine\n\nProvider-neutral Connection records (no vendor lock-in):\n\n```json\n{\n  \"connectionId\": \"github-primary\",\n  \"provider\": \"github\",\n  \"credentialProvider\": \"descope\",\n  \"authorizationRef\": \"descope:github:auth_123\",\n  \"status\": \"connected\",\n  \"capabilities\": [\"repo.read\", \"repo.write\"],\n  \"lastValidatedAt\": \"2026-07-17T14:32:00Z\",\n  \"health\": \"healthy\",\n  \"owner\": \"user_123\",\n  \"tenantId\": \"tenant_456\",\n  \"createdAt\": \"2026-07-17T10:00:00Z\",\n  \"lastUsedAt\": \"2026-07-17T14:30:00Z\"\n}\n```\n\n**Key constraint**: `authorizationRef` is the **only** bridge to Descope. IW never stores credentials directly.\n\n---\n\n## Runtime Execution Pattern\n\nEvery capability execution follows the same flow:\n\n```\nHermes (orchestrator)\n    │\n    ▼\nCapability Selection (authorizationRef required)\n    │\n    ▼\nProvider Management MCP ◄─── ALL PROVIDER LOGIC CONFINED HERE\n    │\n    ├─ Descope Adapter (resolve authorizationRef → credentials)\n    │     │\n    │     ▼\n    │  Descope (returns fresh credentials)\n    │     │\n    │     ▼\n    │  Temporary Credential (in-memory, never persisted)\n    │\n    ├─ Provider API (GitHub, Salesforce, Slack, etc.)\n    │     │\n    │     ▼\n    │  Operation Result\n    │\n    ▼\nCredential Destroyed (immediately after use)\n    │\n    ▼\nResult returned to Hermes\n    │\n    ▼\nContinuity updated (operation record + outcome)\n```\n\n**Principle**: No access token persists beyond execution scope.\n\n---\n\n## Connection Abstraction\n\nBusiness logic never couples to Descope concepts:\n\n```typescript\ninterface Connection {\n  id: string; // UUID\n  provider: string; // \"github\", \"salesforce\", \"slack\"\n  authorizationRef: string; // \"descope:github:auth_123\" or provider-agnostic\n  status: \"connected\" | \"disconnected\" | \"error\" | \"refreshing\";\n  scopes: string[]; // [\"repo.read\", \"repo.write\"]\n  owner: string; // user_id\n  tenantId: string;\n  createdAt: Date;\n  lastUsedAt: Date;\n}\n```\n\n**Future-proofing**: Replace Descope with Auth0, Okta, or internal service without touching Hermes, Capability Fabric, or providers.\n\n---\n\n## Architecture Layers\n\n```\nUsers\n    │\n    ▼\nDescope Auth (inbound: login, SSO, OAuth)\n    │\n    ▼\nGateway (mapDescopePrincipal, context envelope)\n    │\n    ▼\nContinuity Bridge (tenant_id, user_id, roles, permissions)\n    │\n    ▼\nMCP Pool (routing dispatcher)\n    │\n    ▼\nProvider Management MCP ◄─── ABSTRACTION LAYER (single source of provider truth)\n    │\n    ├─ Descope Adapter (for V0; future: Auth0 Adapter, Okta Adapter, etc.)\n    │\n    ├─ Provider Implementations (GitHub, Salesforce, Slack, HubSpot, Linear, etc.)\n    │\n    └─ Connection Health Checks\n    │\n    ▼\nExternal APIs (GitHub, Salesforce, Slack, etc.)\n```\n\n---\n\n## Connection Flow (OAuth to Execution)\n\n### 1. User Initiates Connection\n\n```\nUser clicks \"Connect GitHub\"\n    ↓\nGovernance checks: does user have INTEGRATION_CONNECT authority?\n    ↓\nIf yes: Provider Management MCP routes to Descope OAuth\nIf no: Error (no permission)\n```\n\n### 2. OAuth Authorization\n\n```\nUser redirected to Descope OAuth consent\n    ↓\nUser grants permissions (scopes)\n    ↓\nDescope callback to /api/v1/provider-management/callback\n    ↓\nProvider Management MCP receives authorizationRef: \"descope:github:auth_123\"\n```\n\n### 3. Connection Stored in Spine\n\n```\nProvider Management MCP returns to Gateway\n    ↓\nGateway creates Connection record:\n  {\n    id: \"github-primary\",\n    provider: \"github\",\n    authorizationRef: \"descope:github:auth_123\",\n    status: \"connected\",\n    ...\n  }\n    ↓\nSpine stores Connection (NO credentials, only authorizationRef)\n```\n\n### 4. Later: Capability Execution\n\n```\nUser triggers \"Merge PR\" (capability)\n    ↓\nCapability Fabric selects route: provider=github, authorizationRef=descope:github:auth_123\n    ↓\nContinuity Bridge routes to Provider Management MCP with authorizationRef\n    ↓\nProvider Management MCP → Descope Adapter: resolve(authorizationRef)\n    ↓\nDescope returns fresh credentials (auto-refreshed if expired)\n    ↓\nGitHub provider executes with credentials\n    ↓\nResult returned\n    ↓\nCredentials destroyed (NOT stored)\n```\n\n---\n\n## Components\n\n### 1. Provider Management MCP (New Core)\n\n**File**: `services/mcp-connector/src/providers/provider-management/index.ts`\n\nResponsibilities:\n\n- Route OAuth flows for all providers\n- Abstract provider-specific logic\n- Resolve authorizationRef to fresh credentials\n- Health checks for all connections\n- Credential lifecycle management\n\n```typescript\nexport interface ProviderManagementMCP {\n  // OAuth flows\n  initiateConnection(provider: string, user: User): Promise<OAuthUrl>;\n  handleCallback(provider: string, code: string, state: string): Promise<Connection>;\n\n  // Credential resolution\n  resolveCredentials(authorizationRef: string): Promise<Credentials>;\n\n  // Connection management\n  listConnections(user: User): Promise<Connection[]>;\n  updateConnectionStatus(connectionId: string, status: string): Promise<void>;\n  deleteConnection(connectionId: string): Promise<void>;\n\n  // Health checks\n  checkHealth(connectionId: string): Promise<HealthStatus>;\n}\n```\n\n### 2. Descope Adapter (V0 Implementation)\n\n**File**: `services/mcp-connector/src/providers/descope-adapter/index.ts`\n\nImplements Provider Management MCP interface for Descope:\n\n```typescript\nexport class DescopeAdapter implements ProviderAdapter {\n  async resolveCredentials(authorizationRef: string): Promise<Credentials> {\n    // Call Descope Management API: GET /v1/auth/connection/{authorizationRef}\n    const connection = await descopeClient.getConnection(authorizationRef);\n\n    // Refresh token if expired\n    if (connection.expiresAt < Date.now()) {\n      connection = await descopeClient.refreshToken(authorizationRef);\n    }\n\n    return {\n      accessToken: connection.accessToken,\n      refreshToken: connection.refreshToken,\n      expiresAt: connection.expiresAt,\n      provider: connection.provider,\n    };\n  }\n\n  async initiateOAuth(provider: string): Promise<string> {\n    const state = crypto.randomUUID();\n    const url = `https://descope.com/oauth/${provider}?state=${state}`;\n    await kv.put(`oauth_state_${state}`, provider, { expirationTtl: 600 });\n    return url;\n  }\n\n  async handleCallback(code: string, state: string): Promise<Connection> {\n    const provider = await kv.get(`oauth_state_${state}`);\n    if (!provider) throw new Error(\"Invalid state\");\n\n    const authResult = await descopeClient.exchangeCode({\n      provider,\n      code,\n      state,\n    });\n\n    return {\n      provider,\n      authorizationRef: authResult.authorizationRef,\n      status: \"connected\",\n      scopes: authResult.scopes,\n    };\n  }\n}\n```\n\n### 3. Spine Connection Model\n\n**File**: `apps/web/src/data/knowledge.ts`\n\n```typescript\nexport interface Connection {\n  id: string;\n  provider: string;\n  authorizationRef: string;\n  status: \"connected\" | \"disconnected\" | \"error\" | \"refreshing\";\n  capabilities: string[];\n  lastValidatedAt: Date;\n  health: \"healthy\" | \"unhealthy\" | \"unknown\";\n  owner: string;\n  tenantId: string;\n  createdAt: Date;\n  lastUsedAt: Date;\n  metadata?: Record<string, any>;\n}\n```\n\n---\n\n## Implementation Priority\n\n| Priority | Task                                                     | Timeline | Blocker       |\n| -------- | -------------------------------------------------------- | -------- | ------------- |\n| 1        | Create Provider Management MCP interface & contract      | 2 days   | None          |\n| 2        | Wire `/api/v1/provider-management/callback` into Gateway | 1 day    | Priority 1    |\n| 3        | Implement Descope Adapter (V0)                           | 3 days   | Priority 1, 2 |\n| 4        | Create Spine Connection model + migrations               | 2 days   | Priority 3    |\n| 5        | Update all providers to use Provider Management MCP      | 5 days   | Priority 3, 4 |\n| 6        | Test end-to-end: connect → execute → health check        | 3 days   | Priority 5    |\n\n**Total**: 2-3 weeks  \n**V0 Ready**: After Priority 4 (Connection model in Spine)  \n**Production Ready**: After Priority 6\n\n---\n\n## Benefits of This Architecture\n\n✅ **Zero vendor lock-in**: Descope is an implementation detail, not architecture  \n✅ **Provider-neutral**: Replace Descope without changing business logic  \n✅ **Clear ownership**: Identity = Descope, Operations = IntegrateWise  \n✅ **Secure**: No credentials in IW state, temporary in-memory credentials only  \n✅ **Auditable**: All operations recorded in Spine + Descope audit trail  \n✅ **Scalable**: Add providers by implementing ProviderAdapter interface  \n✅ **Governance enforced**: Authority checks at every connection point  \n✅ **Future-proof**: Architecture supports Auth0, Okta, internal SSO, etc.\n\n---\n\n## Comparison: V1.0 vs V1.1\n\n| Aspect               | V1.0                    | V1.1                                 |\n| -------------------- | ----------------------- | ------------------------------------ |\n| Descope role         | Single source of truth  | Identity + credential provider       |\n| IntegrateWise role   | State storage only      | Operations + governance + continuity |\n| Provider abstraction | None (Descope-specific) | Provider Management MCP              |\n| Extensibility        | Add more Descope apps   | Add ProviderAdapter implementations  |\n| Vendor lock-in       | High (tightly coupled)  | Low (pluggable adapters)             |\n| Future migration     | Difficult               | Straightforward (new adapter)        |\n\n---\n\n## References\n\n- Descope Outbound Connections: https://docs.descope.com/build/outbound-connections/\n- MCP Descope Adapter: `services/mcp-connector/src/providers/descope/`\n- Continuity Bridge: `services/mcp-connector/src/continuity-bridge.ts`\n- Integration Manager: `apps/web/src/components/connectivity/integrations-hub.tsx`\n"}