How to Set Up Supabase Authentication for the GPT-Image-2 Website
The GPT-Image-2 website uses Supabase Auth with Google OAuth for user sign-in, storing sessions via a singleton client in src/supabaseClient.js while reserving the service-role key for server-side credit and billing operations.
The freestylefly/awesome-gpt-image-2 repository implements a complete authentication and billing system using Supabase. Setting up Supabase authentication requires configuring the Google OAuth provider, applying database migrations for user credits and billing, and integrating the Supabase client wrapper into the React frontend.
Prerequisites and Project Structure
Before configuring authentication, ensure you have created a Supabase project at supabase.com. The repository relies on specific database tables and RPC functions defined in the migration files located in the supabase/migrations/ directory. These migrations establish the schema for tracking user credits, membership billing, and payment processing.
Key components you will configure include:
- Supabase Auth Settings: Enable Google provider and optionally disable email authentication
- Database Migrations: Execute SQL files including
202605090001_user_credits.sql,20260509090000_membership_billing.sql, and20260721090000_alipay_webpay.sql - Environment Variables: Expose
VITE_SUPABASE_URLandVITE_SUPABASE_ANON_KEYto the client while keepingSUPABASE_SERVICE_ROLE_KEYserver-side only - Client Wrapper: The
src/supabaseClient.jsfile initializes the Supabase client singleton used throughout the application
Configuring Supabase Auth in the Dashboard
To enable authentication, navigate to the Authentication → Settings section of your Supabase dashboard.
First, enable the Google provider by adding your Google Cloud Console Client ID and Client Secret. If you require a Google-only sign-in experience as implemented in the source code, disable the Email provider in the same settings panel.
Next, configure the Redirect URLs to include your production domain (e.g., https://gpt-image2.canghe.ai) and local development URLs (e.g., http://localhost:5173). This allows Supabase to return users to the correct endpoint after successful OAuth authentication.
Database Schema and Migrations
The authentication system relies on tables and functions defined in the migration files. Execute these SQL files against your Supabase database via the SQL Editor or CLI:
supabase/migrations/202605090001_user_credits.sql: Creates theuser_creditstable and RPC functions for credit managementsupabase/migrations/20260509090000_membership_billing.sql: Defines membership plans, Stripe orders, and billing-related RPCssupabase/migrations/20260721090000_alipay_webpay.sql: Configures Alipay payment integration (optional)
These migrations create the backend infrastructure that stores user data and handles credit deductions when users generate images.
Client-Side Integration
Initializing the Supabase Client
The src/supabaseClient.js file creates a singleton client instance that the entire frontend uses to interact with Supabase Auth. This file reads the public environment variables prefixed with VITE_ (Vite-specific) to ensure they are available at runtime.
// src/supabaseClient.js
import { createClient } from '@supabase/supabase-js';
const supabaseUrl = import.meta.env.VITE_SUPABASE_URL;
const supabaseAnonKey = import.meta.env.VITE_SUPABASE_ANON_KEY;
export const supabase = createClient(supabaseUrl, supabaseAnonKey);
Implementing Google OAuth Sign-In
To trigger authentication, components call supabase.auth.signInWithOAuth() with the Google provider. This method redirects the user to Google's consent screen and handles the OAuth flow automatically.
// Example component implementation
import { supabase } from '../supabaseClient';
export default function SignInButton() {
const handleLogin = async () => {
const { error } = await supabase.auth.signInWithOAuth({
provider: 'google'
});
if (error) console.error('Authentication error:', error);
};
return (
<button onClick={handleLogin} className="google-btn">
Sign in with Google
</button>
);
}
Handling Authentication State
The entry point src/main.jsx initializes the application and can check for existing sessions using supabase.auth.getUser(). Protected routes should verify the current user before rendering sensitive components.
// src/components/ProtectedRoute.jsx
import { useEffect, useState } from 'react';
import { supabase } from '../supabaseClient';
import { Navigate } from 'react-router-dom';
export default function ProtectedRoute({ children }) {
const [user, setUser] = useState(null);
const [loading, setLoading] = useState(true);
useEffect(() => {
supabase.auth.getUser().then(({ data: { user } }) => {
setUser(user);
setLoading(false);
});
}, []);
if (loading) return <div>Loading…</div>;
return user ? children : <Navigate to="/login" />;
}
Server-Side Privileged Operations
For operations requiring elevated privileges—such as adjusting user credits or processing payments—the application uses the Service Role Key. This key bypasses Row Level Security (RLS) and must never be exposed to the browser. Server-side API routes (e.g., api/billing/checkout.js) initialize a separate client instance using SUPABASE_SERVICE_ROLE_KEY.
// Server-side API route example
import { createClient } from '@supabase/supabase-js';
const supabase = createClient(
process.env.VITE_SUPABASE_URL,
process.env.SUPABASE_SERVICE_ROLE_KEY
);
export default async function handler(req, res) {
const { userId, adjustment } = req.body;
const { data, error } = await supabase.rpc('adjust_user_credits', {
uid: userId,
delta: adjustment,
});
if (error) return res.status(500).json({ error });
res.status(200).json({ data });
}
Environment Variables Configuration
Create a .env file based on the repository's .env.example template. The following variables are required:
VITE_SUPABASE_URL: Your Supabase project URL (public)VITE_SUPABASE_ANON_KEY: Your Supabase anonymous/public key (public)SUPABASE_SERVICE_ROLE_KEY: Your Supabase service role key (server-only)
When deploying to Vercel as specified in the README, add these variables to your project settings. The VITE_ prefix ensures Vite exposes these variables to the client-side code, while the service role key remains server-side only.
Summary
- Create a Supabase project and run the migration files in
supabase/migrations/to establish the user credits and billing schema - Enable Google OAuth in Authentication → Settings and optionally disable Email authentication for a Google-only flow
- Configure redirect URLs for both production and local development environments
- Initialize the client in
src/supabaseClient.jsusingVITE_SUPABASE_URLandVITE_SUPABASE_ANON_KEY - Use
supabase.auth.signInWithOAuth({ provider: 'google' })to trigger sign-in from the frontend - Reserve
SUPABASE_SERVICE_ROLE_KEYfor server-side operations that modify user credits or billing data - Reference
src/main.jsxfor initialization patterns and implement protected routes usingsupabase.auth.getUser()
Frequently Asked Questions
How do I disable email authentication and force Google-only sign-in?
Navigate to Authentication → Settings in your Supabase dashboard and disable the Email provider while keeping the Google provider enabled. This configuration matches the repository's intended authentication flow where users must sign in with Google.
What is the difference between the Anon Key and the Service Role Key?
The Anon Key is safe to expose in browser code and respects Row Level Security (RLS) policies. The Service Role Key has full database access and bypasses RLS, making it suitable for server-side operations like adjusting credits via the adjust_user_credits RPC function. Never expose the Service Role Key in client-side code.
Which migration files are required for the authentication system to function?
You must execute 202605090001_user_credits.sql for basic credit tracking and 20260509090000_membership_billing.sql for subscription management. The 20260721090000_alipay_webpay.sql migration is only necessary if you plan to support Alipay payments. These files create the tables and RPC functions that the frontend expects when calling credit-related operations.
How does the frontend maintain the user session after sign-in?
The Supabase client stores the session in localStorage automatically. Components can retrieve the current user by calling supabase.auth.getUser(), which returns the user object and JWT. This session persists across page reloads until the user signs out or the token expires.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →