Launchpad Integration Guide

Integrate unified Single Sign-On and credit-based billing into your applications with Launchpad

Single Sign-OnSecureFast Integration

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.

Single Sign-On

User logs into Launchpad → automatically authenticated in all your apps via shared Supabase session

Shared Credits

One credit pool across all apps. Users buy credits once in Launchpad, use them everywhere

Simple Integration

Share Supabase credentials, install client, check auth status. Deploy in minutes

How It Works

1

User logs into Launchpad

User signs up or logs in at your Launchpad instance

2

Supabase creates session

Supabase Auth creates a JWT token and stores it in cookies (accessible across all your domains sharing the same Supabase project)

3

User visits your app

Your application checks for Supabase session using the same credentials

4

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:

Pattern A: Same Database
Simplest setup

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
Pattern B: Separate DatabaseRecommended
Better isolation

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

Step 1: Install Supabase Client
npm install @supabase/supabase-js @supabase/ssr
Step 2: Configure Environment Variables
Add these to your .env.local file
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

Step 3: Create Supabase Client
Create lib/supabase/client.ts
import { createBrowserClient } from '@supabase/ssr'

export function createClient() {
  return createBrowserClient(
    process.env.NEXT_PUBLIC_SUPABASE_URL!,
    process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!
  )
}
Step 4: Check Auth in Your App
Example Next.js component
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.

Step 1: Install Dependencies
npm install @supabase/supabase-js jose
Step 2: Configure Environment Variables
You need both Launchpad AND your app's Supabase credentials
# 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.

Step 3: Create JWT Verification Utility
lib/auth/verify-launchpad.ts
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 }
  }
}
Step 4: Create Auth Verification API
app/api/auth/verify/route.ts
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 })
  }
}
Step 5: Use in Your App
Client component example
'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.

Get Your API Key
  1. Log in to Launchpad admin dashboard
  2. Go to Apps section and register your app
  3. Copy the generated API Key
  4. 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.

GET/api/v1/credits/balance

Check 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()
POST/api/v1/credits/deduct

Deduct 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?

Admin Dashboard

Register your app and get API keys

Go to Admin
Back to Home

Return to Launchpad homepage

Home