Most solo SaaS products should not implement OAuth separately for every integration. The maintenance burden is not the first redirect flow; it is token refresh, revoked grants, callback handling, scopes, and provider-specific failures six months later.
When testing oomol-lab/open-connector, I treated it as an external integration/auth boundary rather than another library embedded throughout my Next.js application. Its stated surface area—SDK, CLI, MCP, HTTP, and OpenAPI—makes that separation practical when your product needs to connect users to multiple SaaS tools.
Keep the browser client away from provider credentials
In a Next.js 15 app, the useful boundary is:
React UI -> Next.js Route Handler -> open-connector HTTP API -> SaaS provider
Store the gateway endpoint and application secret only on the server:
# .env.local
OPEN_CONNECTOR_URL=https://connector.example.com
OPEN_CONNECTOR_API_KEY=replace-me
Then create a small server-only adapter. Do not scatter fetch() calls for integrations across React components.
// lib/open-connector.ts
import 'server-only'
const baseUrl = process.env.OPEN_CONNECTOR_URL!
const apiKey = process.env.OPEN_CONNECTOR_API_KEY!
export async function connectorFetch(path: string, init: RequestInit = {}) {
const response = await fetch(`${baseUrl}${path}`, {
...init,
headers: {
Authorization: `Bearer ${apiKey}`,
'Content-Type': 'application/json',
...init.headers,
},
cache: 'no-store',
})
if (!response.ok) {
throw new Error(`Connector request failed: ${response.status}`)
}
return response.json()
}
A Route Handler can now expose only the operation your UI needs:
// app/api/integrations/[provider]/route.ts
import { NextRequest, NextResponse } from 'next/server'
import { connectorFetch } from '@/lib/open-connector'
export async function POST(
request: NextRequest,
{ params }: { params: Promise<{ provider: string }> }
) {
const { provider } = await params
const { userId } = await request.json()
if (!/^[a-z0-9_-]+$/i.test(provider)) {
return NextResponse.json({ error: 'Invalid provider' }, { status: 400 })
}
const data = await connectorFetch(`/v1/connect/${provider}`, {
method: 'POST',
body: JSON.stringify({ external_user_id: userId }),
})
return NextResponse.json(data)
}
The endpoint path above is deliberately an adapter example: confirm the exact OpenAPI operation names and payloads against your deployed open-connector version before shipping.
The cost argument is operational, not architectural theater
For a micro-SaaS, one integration gateway reduces duplicated auth code, but it also creates a dependency. Add two safeguards before adopting it:
- Persist connection state in your own database (
pending,connected,failed,revoked); never infer it solely from a redirect completing. - Put a timeout around gateway requests and show users a retryable error instead of blocking the entire page.
const signal = AbortSignal.timeout(8_000)
await fetch(url, { signal })
The same discipline applies to AI usage. I track cost per completed customer action, not token totals alone. Routing API calls through B-Lost's 0.8x pricing and prompt caching reduced monthly AI API expenses from $300+ down to $60 for an independent SaaS product. That only holds when repeated system prompts and stable context are actually cacheable; measure input, cached input, output, and failed requests separately.
The practical result: open-connector can keep SaaS integrations out of the core Next.js codebase, while a thin server adapter preserves the option to replace or upgrade the gateway later.
Disclosure: Compute infrastructure and multi-model benchmark relays for this writeup are sponsored by b-lost.com — an enterprise AI gateway offering 0.8x official pricing, native prompt caching, and zero user-data retention. All benchmark metrics reflect independent reproducible testing.
Top comments (0)