{"slug":"architecture/CONTINUITY_BRIDGE_SIMPLE","title":"Continuity Bridge: Simple OAuth Implementation","section":"architecture","sectionLabel":"Architecture","status":"unclassified","type":"document","path":"architecture/CONTINUITY_BRIDGE_SIMPLE.mdx","bytes":7108,"description":null,"updated":null,"source":"integratewise/Integratewise-docs-wiki","content":"\n\n> **Tier C — Historical.** This document is a point-in-time snapshot preserved for reference. For current architecture, see [CANONICAL_PLATFORM_ARCHITECTURE.md](../architecture/CANONICAL_PLATFORM_ARCHITECTURE.md).\n\n## One Connection, Multiple Frontends\n\n**The Motion**: Marketplace app clicked → OAuth redirect → Features available\n\n---\n\n## Architecture\n\n```\nMarketplace App (Claude, ChatGPT, etc.)\n        ↓\nUser clicks \"Connect IntegrateWise\"\n        ↓\nRedirect to: https://integratewise.com/auth?app=claude&redirect_uri=...\n        ↓\nContinuity Bridge (OAuth Endpoint)\n  • Validate app + redirect_uri\n  • User enters email + org name\n  • Create tenant + user (if new)\n  • Issue JWT token\n        ↓\nRedirect back to app with JWT\n        ↓\nApp stores JWT locally\n        ↓\nAll subsequent API calls include JWT\n        ↓\nFeatures automatically available (token validation = auth check)\n```\n\n---\n\n## Implementation: 3 Files\n\n### 1. OAuth Endpoint\n\n**File**: `services/continuity-bridge/src/oauth-handler.ts`\n\n```typescript\n\nconst router = Router();\n\n// Supported marketplace apps\nconst APPS = {\n  claude: {\n    redirect_uri_pattern: /^claude-extension:\\/\\/callback$/,\n    name: 'Claude Desktop'\n  },\n  chatgpt: {\n    redirect_uri_pattern: /^https:\\/\\/chatgpt\\.com\\/callback$/,\n    name: 'ChatGPT'\n  },\n  perplexity: {\n    redirect_uri_pattern: /^https:\\/\\/perplexity\\.com\\/callback$/,\n    name: 'Perplexity'\n  },\n  replit: {\n    redirect_uri_pattern: /^https:\\/\\/replit\\.com\\/callback$/,\n    name: 'Replit'\n  },\n  lovable: {\n    redirect_uri_pattern: /^https:\\/\\/lovable\\.dev\\/callback$/,\n    name: 'Lovable'\n  }\n};\n\n// GET /auth/authorize?app=claude&redirect_uri=...&email=...&org_name=...\nrouter.get('/authorize', async (req: Request, res: Response) => {\n  try {\n    const { app, redirect_uri, email, org_name } = req.query;\n\n    // 1. Validate app + redirect_uri\n    if (!app || typeof app !== 'string' || !APPS[app as keyof typeof APPS]) {\n      return res.status(400).json({ error: 'Invalid app' });\n    }\n\n    const appConfig = APPS[app as keyof typeof APPS];\n    if (!appConfig.redirect_uri_pattern.test(String(redirect_uri))) {\n      return res.status(400).json({ error: 'Invalid redirect_uri' });\n    }\n\n    // 2. Create tenant + user (or get existing)\n    const tenant = await db.tenant.findOrCreate({\n      where: { email: String(email) },\n      defaults: {\n        org_name: String(org_name) || 'My Org',\n        email: String(email),\n        created_at: new Date()\n      }\n    });\n\n    const user = await db.user.findOrCreate({\n      where: { tenant_id: tenant.id, email: String(email) },\n      defaults: {\n        tenant_id: tenant.id,\n        email: String(email),\n        created_at: new Date()\n      }\n    });\n\n    // 3. Issue JWT token\n    const jwt_token = jwt.sign(\n      {\n        user_id: user.id,\n        tenant_id: tenant.id,\n        email: user.email,\n        app: app,\n        iat: Date.now() / 1000\n      },\n      process.env.JWT_SECRET,\n      { expiresIn: '24h' }\n    );\n\n    // 4. Redirect back to app with token\n    const callback_url = new URL(String(redirect_uri));\n    callback_url.searchParams.set('token', jwt_token);\n    callback_url.searchParams.set('tenant_id', tenant.id);\n    \n    res.redirect(callback_url.toString());\n  } catch (error) {\n    console.error('OAuth error:', error);\n    res.status(500).json({ error: 'Authorization failed' });\n  }\n});\n\n```\n\n### 2. JWT Validation Middleware\n\n**File**: `services/gateway/src/middleware/jwt-validator.ts`\n\n```typescript\n\nexport interface AuthenticatedRequest extends Request {\n  user_id?: string;\n  tenant_id?: string;\n  email?: string;\n}\n\n  const token = req.headers.authorization?.replace('Bearer ', '');\n\n  if (!token) {\n    return res.status(401).json({ \n      error: 'Unauthorized',\n      connect_url: 'https://integratewise.com/auth?app=...'\n    });\n  }\n\n  try {\n    const decoded = jwt.verify(token, process.env.JWT_SECRET) as {\n      user_id: string;\n      tenant_id: string;\n      email: string;\n    };\n\n    req.user_id = decoded.user_id;\n    req.tenant_id = decoded.tenant_id;\n    req.email = decoded.email;\n\n    next();\n  } catch (error) {\n    return res.status(401).json({ error: 'Invalid token' });\n  }\n}\n```\n\n### 3. Feature Gate Logic\n\n**File**: `services/gateway/src/middleware/feature-gate.ts`\n\n```typescript\n\n  // If token is valid (JWT validation passed), user has access to ALL features\n  \n  if (!req.tenant_id || !req.user_id) {\n    return res.status(401).json({ error: 'Not authenticated' });\n  }\n\n  // Token is valid = full feature surface available\n  // No additional checks needed\n  \n  next();\n}\n```\n\n---\n\n## Usage: Multi-Frontend Integration\n\n### Claude Desktop\n\n```json\n{\n  \"oauth_redirect\": \"https://integratewise.com/auth\",\n  \"app\": \"claude\",\n  \"redirect_uri\": \"claude-extension://callback\"\n}\n```\n\nWhen user clicks \"Connect IntegrateWise\":\n```\n→ https://integratewise.com/auth?app=claude&redirect_uri=claude-extension://callback&email=user@company.com&org_name=Company%20Name\n→ User sees OAuth form\n→ Continues to authorize\n→ Redirected back: claude-extension://callback?token=eyJhbGc...\n→ Claude stores token locally\n→ All subsequent MCP calls include: Authorization: Bearer eyJhbGc...\n```\n\n### ChatGPT Custom Action\n\n```json\n{\n  \"url\": \"https://integratewise.com/mcp\",\n  \"auth\": {\n    \"type\": \"oauth\",\n    \"client_id\": \"chatgpt-client-id\",\n    \"authorization_url\": \"https://integratewise.com/auth?app=chatgpt\",\n    \"token_url\": \"https://integratewise.com/auth/token\"\n  }\n}\n```\n\n### All Other Platforms\n\nSame pattern:\n- Different `app` parameter\n- Different `redirect_uri` (but all redirect back with JWT)\n- Same JWT validation\n- Same feature gate\n\n---\n\n## Deployment Checklist\n\n- [ ] OAuth endpoint deployed\n- [ ] JWT generation verified (24-hour expiration)\n- [ ] JWT validation middleware added to Gateway\n- [ ] Feature gate middleware added to all routes\n- [ ] All 5 marketplace apps configured with correct redirect_uris\n- [ ] Test: Manual OAuth flow (authorize → token → API call)\n- [ ] Test: Verify all 5 apps redirect correctly\n- [ ] Production: Enable JWT signing with real secret\n- [ ] Production: Enable HTTPS only for redirect_uris\n\n---\n\n## Success Metric\n\n**Click marketplace app → OAuth → Features available**\n\nIf user has valid JWT token, they have access to everything. No feature flags, no additional checks, no complexity.\n\nBinary state:\n- ❌ No token → Show \"Connect\" button\n- ✅ Valid token → Show everything (Spine, Agent Lee, Memory, Tasks, Metrics)\n\nThat's the entire motion.\n"}