Launchpad Integration Guide
Integrate unified Single Sign-On and credit-based billing into your applications with Launchpad
Overview
Launchpad is your centralized authentication and billing hub. Users log in once to Launchpad, and all your applications automatically share that authenticated session. No separate logins, no duplicate user management—just seamless access across your entire platform.
User logs into Launchpad → automatically authenticated in all your apps via shared Supabase session
One credit pool across all apps. Users buy credits once in Launchpad, use them everywhere
Share Supabase credentials, install client, check auth status. Deploy in minutes
How It Works
User logs into Launchpad
User signs up or logs in at your Launchpad instance
Supabase creates session
Supabase Auth creates a JWT token and stores it in cookies (accessible across all your domains sharing the same Supabase project)
User visits your app
Your application checks for Supabase session using the same credentials
Automatically authenticated
User is already logged in! Your app gets their profile, email, and credit balance. No login screen needed
Architecture Patterns
Choose the integration pattern that fits your needs:
Your app uses the same Supabase project as Launchpad for both auth and data storage.
✓ Pros:
- Simplest integration
- Direct access to profiles table
- Automatic session sharing
✗ Cons:
- All data in one database
- Less isolation between apps
Your app has its own Supabase database but verifies auth tokens from Launchpad.
✓ Pros:
- Data isolation per app
- Independent scaling
- Still shares auth (SSO)
✗ Cons:
- Requires JWT verification
- Slightly more complex setup
Integration Steps
Choose your pattern below
Follow Pattern A for same database OR Pattern B for separate database
Pattern A: Same Database Setup
npm install @supabase/supabase-js @supabase/ssr
NEXT_PUBLIC_SUPABASE_URL=<your-launchpad-supabase-url> NEXT_PUBLIC_SUPABASE_ANON_KEY=<your-launchpad-anon-key> LAUNCHPAD_API_KEY=<your-app-api-key>
⚠️ Replace placeholders with the same Supabase credentials used by Launchpad
import { createBrowserClient } from '@supabase/ssr'
export function createClient() {
return createBrowserClient(
process.env.NEXT_PUBLIC_SUPABASE_URL!,
process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!
)
}import { createClient } from '@/lib/supabase/client'
import { useEffect, useState } from 'react'
export default function MyApp() {
const [user, setUser] = useState(null)
const [profile, setProfile] = useState(null)
const supabase = createClient()
useEffect(() => {
supabase.auth.getUser().then(({ data }) => {
if (data.user) {
setUser(data.user)
// Get profile with credit balance
supabase
.from('profiles')
.select('*')
.eq('id', data.user.id)
.single()
.then(({ data: profile }) => {
setProfile(profile)
})
} else {
// Redirect to Launchpad login
window.location.href = 'https://go.wirings.io/login'
}
})
}, [])
if (!user) return <div>Loading...</div>
return (
<div>
<p>Welcome, {user.email}!</p>
<p>Credits: {profile?.credit_balance}</p>
</div>
)
}Pattern B: Separate Database Setup
Use this if your app has its own Supabase project but wants to verify users from Launchpad.
npm install @supabase/supabase-js jose
# Launchpad credentials for auth verification LAUNCHPAD_SUPABASE_URL=<launchpad-supabase-url> LAUNCHPAD_JWT_SECRET=<launchpad-jwt-secret> # Your app's own database NEXT_PUBLIC_SUPABASE_URL=<your-own-supabase-url> NEXT_PUBLIC_SUPABASE_ANON_KEY=<your-own-anon-key> # For credit API calls LAUNCHPAD_API_KEY=<your-app-api-key>
ℹ️ Contact your Launchpad admin for the JWT secret. Replace all placeholders with actual values.
import { jwtVerify } from 'jose'
export async function verifyLaunchpadToken(token: string) {
try {
const secret = new TextEncoder().encode(
process.env.LAUNCHPAD_JWT_SECRET!
)
const { payload } = await jwtVerify(token, secret)
return {
verified: true,
userId: payload.sub as string,
email: payload.email as string
}
} catch (error) {
return { verified: false }
}
}import { cookies } from 'next/headers'
import { verifyLaunchpadToken } from '@/lib/auth/verify-launchpad'
export async function GET() {
const cookieStore = await cookies()
// Get Supabase session cookie from Launchpad domain
// Pattern: sb-<project-ref>-auth-token
let authToken = null
for (const [name, cookie] of cookieStore.getAll().entries()) {
if (name.startsWith('sb-') && name.endsWith('-auth-token')) {
authToken = cookie.value
break
}
}
if (!authToken) {
return Response.json({ authenticated: false })
}
try {
const session = JSON.parse(authToken)
const verification = await verifyLaunchpadToken(
session.access_token
)
if (!verification.verified) {
return Response.json({ authenticated: false })
}
// User authenticated! You can now store in YOUR database
return Response.json({
authenticated: true,
user: {
id: verification.userId,
email: verification.email
}
})
} catch {
return Response.json({ authenticated: false })
}
}'use client'
import { useEffect, useState } from 'react'
import { createClient } from '@/lib/supabase/client' // Your own DB
export default function MyApp() {
const [user, setUser] = useState(null)
const [loading, setLoading] = useState(true)
const supabase = createClient() // Your own Supabase
useEffect(() => {
async function checkAuth() {
// Verify Launchpad session
const response = await fetch('/api/auth/verify')
const data = await response.json()
if (!data.authenticated) {
// Redirect to Launchpad for login
window.location.href = 'https://go.wirings.io/login'
return
}
setUser(data.user)
// Now you can use YOUR database with the verified user
const { data: profile } = await supabase
.from('user_profiles') // Your own table
.select('*')
.eq('user_id', data.user.id)
.single()
setLoading(false)
}
checkAuth()
}, [])
if (loading) return <div>Loading...</div>
return <div>Welcome, {user.email}!</div>
}Pattern B Benefits
Your app has complete database isolation while still participating in Launchpad's SSO. Users log in once to Launchpad, and your app verifies their identity via JWT, then stores app-specific data in your own Supabase project.
Credit Management
Once authenticated, your app can check balances and deduct credits using Launchpad's API.
- Log in to Launchpad admin dashboard
- Go to Apps section and register your app
- Copy the generated API Key
- Add to environment: LAUNCHPAD_API_KEY
Server-side only
Never expose your API key in client-side code. Use server actions or API routes only.
/api/v1/credits/balanceCheck a user's current credit balance.
Example Usage
// Server-side API route
const response = await fetch(
`https://go.wirings.io/api/v1/credits/balance?user_id=${userId}`,
{
headers: {
'X-App-API-Key': process.env.LAUNCHPAD_API_KEY!
}
}
)
const { credit_balance } = await response.json()/api/v1/credits/deductDeduct credits when user uses a feature.
Example Usage
// Server action
const response = await fetch('https://go.wirings.io/api/v1/credits/deduct', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-App-API-Key': process.env.LAUNCHPAD_API_KEY!
},
body: JSON.stringify({
user_id: userId,
amount: 5,
description: 'AI generation'
})
})
const result = await response.json()
if (!result.success) {
// Handle insufficient credits
throw new Error('Not enough credits')
}Need Help?
Register your app and get API keys
Go to AdminReturn to Launchpad homepage
Home