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