How User Authentication Works in the GPT-Image2 Application: A Complete Guide

GPT-Image2 uses Supabase for user authentication, implementing JWT-based session management with automatic token refresh on the client and Bearer token verification on the server.

The freestylefly/awesome-gpt-image-2 repository demonstrates a modern, split-architecture approach to user authentication. By leveraging Supabase—a hosted Postgres and authentication platform—the application handles identity verification across both browser and serverless environments. This implementation ensures secure profile management while maintaining seamless user experiences through persistent sessions and social login providers like Google and GitHub.

Client-Side Session Management

The front-end establishes a persistent authentication state using the Supabase JavaScript client. This configuration automatically manages token lifecycles and session detection without manual intervention.

Initializing the Supabase Client

In src/supabaseClient.js, the application creates a global Supabase instance using environment variables injected by Vite during the build process:

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 = isSupabaseConfigured
  ? createClient(supabaseUrl, supabaseAnonKey, {
      auth: {
        autoRefreshToken: true,
        detectSessionInUrl: true,
        persistSession: true
      }
    })
  : null;

The createClient function accepts three critical authentication settings:

  • autoRefreshToken – Automatically refreshes expired JWTs in the background
  • detectSessionInUrl – Captures authentication callbacks from OAuth providers like Google
  • persistSession – Stores the session in the browser's localStorage for cross-page persistence

Social Authentication Flow

When users initiate sign-in, the client redirects to the OAuth provider and returns with a valid session:

import { supabase } from './supabaseClient';

// Initiate Google OAuth flow
await supabase.auth.signInWithOAuth({ provider: 'google' });

Upon successful authentication, Supabase stores a JSON Web Token (JWT) in the browser. This token is automatically attached to subsequent API requests via the Authorization header.

Server-Side Token Verification

API routes in the /api directory verify incoming requests using the Supabase service role key, which bypasses Row Level Security (RLS) and allows administrative user verification.

Extracting Bearer Tokens

The getAuthContext function in api/_lib/supabase.js serves as the primary authentication middleware. It extracts the JWT from the standard Authorization: Bearer <token> header:

export async function getAuthContext(req, options = {}) {
  const token = getBearerToken(req);
  
  if (!token) {
    return allowAnonymous 
      ? { user: null, profile: null, token: null, client }
      : { error: 'AUTH_REQUIRED', status: 401 };
  }
  
  // Validation logic continues...
}

Validating JWTs with Supabase Admin

Once extracted, the server validates the token against Supabase's authentication service using the admin client:

const { data, error } = await client.auth.getUser(token);

if (error || !data?.user) {
  return { error: 'AUTH_REQUIRED', status: 401 };
}

The client.auth.getUser method contacts Supabase's authentication servers to verify the JWT signature and expiration, returning the associated user record if valid.

Profile Synchronization

After authentication validation, the system ensures database consistency through ensureProfileForUser:

const profile = await ensureProfileForUser(data.user);
return { user: data.user, profile, token, client };

This function creates or updates a corresponding row in the profiles table, linking the Supabase auth user to application-specific metadata. The returned profile object contains normalized user data safe for client consumption.

Protecting API Endpoints

The /api/me.js route demonstrates production-ready authentication patterns, supporting both read-only anonymous access and write-restricted authenticated operations.

The Authentication Context Helper

Route handlers import getAuthContext to establish security boundaries:

import { getAuthContext } from './_lib/supabase';

const auth = await getAuthContext(req, { 
  allowAnonymous: req.method === 'GET' 
});

if (auth.error) {
  return json(res, auth.status || 401, { ok: false, error: auth.error });
}

This pattern returns a structured object containing:

  • user – The Supabase auth user object
  • profile – The application-specific profile record
  • token – The validated JWT string
  • client – The authenticated Supabase client instance

Handling Anonymous vs Authenticated Requests

The endpoint implements conditional access based on HTTP method:

  • GET requests – Allow anonymous access (returns null profile if unauthenticated)
  • PATCH requests – Require valid authentication; rejects requests with 401 if auth.error exists
// Example protected handler
export default async function handler(req, res) {
  const auth = await getAuthContext(req);
  
  if (auth.error) {
    return res.status(auth.status).json({ error: auth.error });
  }
  
  // Safe to use auth.profile and auth.user
  res.json({ user: auth.profile });
}

Admin and Privileged Operations

Privileged routes utilize getSupabaseAdminClient and isSuperAdminEmail functions to restrict access to billing management and community administration features. These functions rely on the SUPABASE_SERVICE_ROLE_KEY environment variable—a server-only secret that grants elevated database permissions.

Unlike the anon key used in the browser, the service role key never exposes itself to client-side code, maintaining security boundaries for administrative functions.

Summary

  • Front-end authentication initializes via src/supabaseClient.js with automatic token refresh and localStorage persistence
  • JWT verification occurs in api/_lib/supabase.js through the getAuthContext middleware, which extracts and validates Bearer tokens
  • Profile synchronization ensures every authenticated user has a corresponding database record via ensureProfileForUser
  • Route protection supports both anonymous read access and mandatory authentication for write operations, as demonstrated in api/me.js
  • Admin security relies on the server-only SUPABASE_SERVICE_ROLE_KEY for privileged database operations

Frequently Asked Questions

What authentication provider does GPT-Image2 use?

GPT-Image2 uses Supabase Auth, a hosted authentication service that supports email/password, magic links, and OAuth providers including Google and GitHub. The implementation stores JWTs in browser localStorage and validates them server-side using Supabase's admin client.

How does GPT-Image2 handle session persistence in the browser?

The Supabase client in src/supabaseClient.js configures persistSession: true, which automatically stores the JWT in localStorage. The autoRefreshToken: true setting ensures expired tokens refresh silently, while detectSessionInUrl: true captures OAuth callbacks without manual token handling.

What happens if a user makes an API request without a valid token?

The getAuthContext function returns a 401 error with the message 'AUTH_REQUIRED' when it cannot extract or validate a Bearer token. For routes configured with allowAnonymous: true, the function returns null values for user and profile instead of an error, permitting limited access to unauthenticated requests.

How are admin-only operations secured in GPT-Image2?

Administrative functions use getSupabaseAdminClient with the SUPABASE_SERVICE_ROLE_KEY environment variable—a secret never exposed to the browser. Helper functions like isSuperAdminEmail check user privileges against an allowlist before permitting access to billing or community management endpoints.

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:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →