# How Supabase Powers Authentication and Billing in Awesome-GPT-Image-2

> Discover how Supabase provides essential backend services for Awesome-GPT-Image-2, managing user authentication, storing profiles, and handling credit and subscription billing.

- Repository: [苍何/awesome-gpt-image-2](https://github.com/freestylefly/awesome-gpt-image-2)
- Tags: case-study
- Published: 2026-08-30

---

**Supabase serves as the central backend infrastructure for the Awesome-GPT-Image-2 project, handling client-side authentication, server-side admin operations, and persistent storage for user profiles, credits, and subscriptions.**

In the `freestylefly/awesome-gpt-image-2` repository, Supabase functions as the complete backend-as-a-service platform that enables user authentication, session management, and monetization features. The implementation splits Supabase capabilities between browser-based client operations and privileged server-side admin functions, creating a secure architecture for managing paid image-generation limits and community features.

## The Dual Architecture: Client and Server Roles

The project utilizes Supabase in two distinct modes that work in tandem to provide secure, scalable user management.

### Client-Side Authentication and Session Handling

On the frontend, the application initializes a standard Supabase client in [`src/supabaseClient.js`](https://github.com/freestylefly/awesome-gpt-image-2/blob/main/src/supabaseClient.js) using the public URL and anonymous key from Vite environment variables. This client manages automatic token refresh, URL-based session detection, and persistent authentication states for logged-in users.

The export includes a configuration checker (`isSupabaseConfigured`) that allows the application to degrade gracefully when Supabase credentials are absent. When configured, the client enables OAuth and magic link authentication flows directly within the browser.

```javascript
// Front-end: create a Supabase client (only if env vars are present)
import { supabase, isSupabaseConfigured } from './supabaseClient.js';

if (isSupabaseConfigured) {
  // Example: sign-in with magic link
  await supabase.auth.signInWithOtp({ email: 'user@example.com' });
}

```

### Server-Side Admin Operations

For API routes, the project employs a privileged Supabase admin client instantiated in [`api/_lib/supabase.js`](https://github.com/freestylefly/awesome-gpt-image-2/blob/main/api/_lib/supabase.js) using the service-role key. This server-side client bypasses row-level security (RLS) policies to perform administrative tasks such as verifying bearer tokens, creating user profiles, and managing billing data.

Key server-side functions include:
- **`getAuthContext(req)`** – Extracts and validates Bearer tokens from incoming requests
- **`ensureProfileForUser`** – Creates or updates user records in the `profiles` table
- **`getMembershipForUser`** – Retrieves subscription status and credit balances
- **`normalizeProfile`** – Formats raw database rows into frontend-compatible objects

```javascript
// Back-end: protect an API route
import { getAuthContext, isSupabaseServerConfigured } from '../_lib/supabase.js';

export async function handler(req, res) {
  if (!isSupabaseServerConfigured()) {
    return res.status(500).json({ error: 'SERVER_NOT_CONFIGURED' });
  }

  const { user, profile, error, status } = await getAuthContext(req);
  if (error) return res.status(status).json({ error });

  // `user` is the Supabase auth user, `profile` contains credits, membership, etc.
  res.json({ 
    message: `Hello ${profile.fullName}!`, 
    credits: profile.creditBalance 
  });
}

```

## Authentication Flow and Session Management

The integration follows a strict flow that ensures security while maintaining flexibility for deployments without backend configuration.

### Configuration Detection

Before initializing any Supabase functionality, both client and server check for required environment variables. The `isSupabaseConfigured` function checks for `SUPABASE_URL` and the anon key on the frontend, while `isSupabaseServerConfigured` validates the service-role key on the backend. If checks fail, the application disables Supabase features and returns specific error codes, allowing the static site to function without database connectivity.

### Token Validation and Profile Resolution

Every protected API route begins with a call to `getAuthContext(req)`, which performs three critical operations:
1. Extracts the `Bearer` token from the HTTP Authorization header
2. Validates the token against Supabase Auth (`client.auth.getUser`)
3. Ensures a corresponding profile exists via `ensureProfileForUser`, creating one if necessary

This context object—containing `{ user, profile, token, client }`—becomes the authority for all subsequent permission checks and database operations.

### Data Persistence Models

Supabase stores persistent data across several interconnected tables:
- **`profiles`** – Core user data including display names, avatar URLs, and credit balances
- **`user_memberships`** – Subscription tiers, expiration dates, and feature flags
- **Audit tables** – Transaction logs for billing events and image generation quotas

Functions like `formatMembership` and `normalizeProfile` transform these raw SQL rows into structured objects consumed by the React frontend.

## Implementing Credit and Billing Systems

The admin client enables secure financial operations that would be impossible with client-side keys alone.

### Checking Credit Balances

Server-side functions query the `profiles` table to retrieve current credit balances before allowing expensive operations like AI image generation. The implementation demonstrates direct table access with the service-role client:

```javascript
// Server-side: fetch a user's credit balance
import { getSupabaseAdminClient } from '../_lib/supabase.js';

async function getUserCredits(userId) {
  const client = getSupabaseAdminClient();
  const { data } = await client
    .from('profiles')
    .select('credit_balance')
    .eq('id', userId)
    .single();
  
  return data?.credit_balance ?? 0;
}

```

### Webhook Handling

The [`api/_lib/supabase.js`](https://github.com/freestylefly/awesome-gpt-image-2/blob/main/api/_lib/supabase.js) module also supports payment webhooks (including Alipay integrations), using the admin client to update membership records and credit balances upon successful transactions. These operations occur in `api/billing/*` routes that verify webhook signatures before modifying database state.

## Summary

- **Supabase provides the complete backend infrastructure** for Awesome-GPT-Image-2, replacing the need for a custom authentication server or database API layer.
- **Dual client architecture** separates public authentication (browser) from privileged operations (server) using distinct API keys and initialization patterns in [`src/supabaseClient.js`](https://github.com/freestylefly/awesome-gpt-image-2/blob/main/src/supabaseClient.js) and [`api/_lib/supabase.js`](https://github.com/freestylefly/awesome-gpt-image-2/blob/main/api/_lib/supabase.js).
- **Automatic profile provisioning** ensures every authenticated user has a corresponding database record with default credits and membership status.
- **Configuration-aware initialization** allows the application to run in static/demo mode without Supabase credentials, returning `SERVER_NOT_CONFIGURED` errors only when backend features are explicitly requested.
- **Row-level security bypass** via the service-role key enables secure credit management and billing webhooks while keeping the frontend client restricted to user-owned data.

## Frequently Asked Questions

### What is the difference between the Supabase client and admin client in this project?

The **client** (in [`src/supabaseClient.js`](https://github.com/freestylefly/awesome-gpt-image-2/blob/main/src/supabaseClient.js)) runs in the browser with an anonymous key and respects row-level security policies, handling login flows and session persistence for individual users. The **admin client** (in [`api/_lib/supabase.js`](https://github.com/freestylefly/awesome-gpt-image-2/blob/main/api/_lib/supabase.js)) runs on the server with a service-role key, bypassing all security policies to manage user profiles, verify tokens, and process billing webhooks across the entire database.

### How does the application handle missing Supabase configuration?

Both frontend and backend implement configuration checks—`isSupabaseConfigured` and `isSupabaseServerConfigured` respectively—that verify the presence of `SUPABASE_URL` and appropriate API keys. If these checks fail, the Supabase client returns `null` on the frontend and API routes return HTTP 500 with `SERVER_NOT_CONFIGURED`, allowing the site to function as a static demo without database connectivity.

### What database tables does Supabase manage for user data?

The schema includes a `profiles` table storing user metadata and credit balances, and a `user_memberships` table tracking subscription tiers and expiration dates. Migration files in `supabase/migrations/*.sql` define these structures, while utility functions like `normalizeProfile` and `formatMembership` translate database rows into application objects.

### How are authentication tokens validated in API routes?

Protected endpoints call `getAuthContext(req)` from [`api/_lib/supabase.js`](https://github.com/freestylefly/awesome-gpt-image-2/blob/main/api/_lib/supabase.js), which extracts the Bearer token from the Authorization header and validates it against Supabase Auth using `client.auth.getUser`. This function also ensures the user has a corresponding profile record via `ensureProfileForUser`, returning a complete context object containing the user identity, profile data, and authenticated client for subsequent database operations.