# Setting Up Google OAuth for Supabase Auth and GA4 on Vercel: Complete Integration Guide

> Integrate Google OAuth with Supabase Auth and GA4 on Vercel. Enable Google provider, run a script for a refresh token, and set environment variables for seamless setup.

- Repository: [苍何/awesome-gpt-image-2](https://github.com/freestylefly/awesome-gpt-image-2)
- Tags: how-to-guide
- Published: 2026-08-31

---

**To set up Google OAuth for Supabase Auth and GA4 on Vercel, enable the Google provider in your Supabase project, execute the `npm run ga4:oauth` helper script to obtain a refresh token, and securely store the service account credentials alongside `SUPABASE_SERVICE_ROLE_KEY` in your Vercel environment variables.**

The **awesome-gpt-image-2** repository demonstrates a production-ready pattern for integrating **Supabase Auth** with **Google Analytics 4 (GA4)** on a serverless Vercel architecture. This guide extracts the exact implementation details from the `freestylefly/awesome-gpt-image-2` source code, covering everything from OAuth configuration to secure JWT validation in API routes.

## Architecture Overview

The authentication and analytics flow follows a secure serverless pattern:

- **Supabase Auth** handles the OAuth exchange with Google, issuing a JWT stored in the browser
- **Vercel API Routes** (`api/*.js`) validate the JWT and proxy requests to protected resources
- **GA4 Client** ([`api/_lib/ga4.js`](https://github.com/freestylefly/awesome-gpt-image-2/blob/main/api/_lib/ga4.js)) uses a service account with `analytics.readonly` scope to fetch reporting data
- **Environment Isolation** keeps privileged keys (`SUPABASE_SERVICE_ROLE_KEY`, GA4 secrets) server-side only

All privileged credentials reside exclusively in Vercel’s serverless environment, while the React frontend communicates via signed JWTs included in the `Authorization: Bearer <token>` header.

## Prerequisites

Before starting, ensure you have:

- A Vercel project connected to your repository
- A Supabase project with Authentication enabled
- A Google Cloud project with the Analytics Data API enabled
- Node.js installed locally to run the OAuth helper script

## Step-by-Step Configuration

### Enable Google OAuth in Supabase Auth

According to the repository’s README (lines 42-44), the application enforces **Google-only sign-in** by disabling the Email provider in Supabase Auth settings.

To configure the provider:

1. Navigate to your Supabase dashboard → Authentication → Providers → Google
2. Create a Google OAuth Web Client in Google Cloud Console
3. Add authorized redirect URIs: `http://localhost:8080/oauth2callback` (for local development) and your production Vercel domain
4. Copy the Client ID and Secret for use in the next steps

### Obtain GA4 Service Account Credentials

The repository includes a dedicated helper script at `scripts/google-analytics-oauth.mjs` that automates the tedious OAuth 2.0 flow for GA4 access:

```bash
npm run ga4:oauth

```

This CLI script prints a URL. Open it in your browser, grant the `analytics.readonly` scope, and paste the returned callback URL into the terminal. The script extracts and displays the `GOOGLE_ANALYTICS_REFRESH_TOKEN` required for server-to-server API calls.

### Configure Vercel Environment Variables

Based on the `.env.example` template and the setup checklist in the README (lines 433-450), configure the following variables in your Vercel project settings:

- `VITE_SUPABASE_URL` – Your Supabase project URL
- `VITE_SUPABASE_ANON_KEY` – Public Supabase client key
- `SUPABASE_SERVICE_ROLE_KEY` – **Private** service role key for server-side operations
- `VITE_GA_MEASUREMENT_ID` – GA4 measurement ID (e.g., `G-XXXXXXX`)
- `GA4_PROPERTY_ID` – Numeric GA4 property identifier
- `GOOGLE_ANALYTICS_CLIENT_ID` – OAuth 2.0 Client ID
- `GOOGLE_ANALYTICS_CLIENT_SECRET` – OAuth 2.0 Client Secret
- `GOOGLE_ANALYTICS_REFRESH_TOKEN` – Token obtained from the helper script

## Core Implementation Files

### Server-Side Authentication ([`api/_lib/supabase.js`](https://github.com/freestylefly/awesome-gpt-image-2/blob/main/api/_lib/supabase.js))

Vercel API routes validate incoming JWTs using the server-side Supabase client. The implementation in [`api/_lib/supabase.js`](https://github.com/freestylefly/awesome-gpt-image-2/blob/main/api/_lib/supabase.js) creates a client with the service role key to verify tokens against the `auth.users` table:

```javascript
// api/_lib/supabase.js
import { createClient } from '@supabase/supabase-js';

export const supabase = createClient(
  process.env.VITE_SUPABASE_URL,
  process.env.VITE_SUPABASE_ANON_KEY,
  { auth: { persistSession: false } }
);

```

API routes import this client to validate the `Authorization` header before executing privileged operations.

### GA4 Reporting Client ([`api/_lib/ga4.js`](https://github.com/freestylefly/awesome-gpt-image-2/blob/main/api/_lib/ga4.js))

The analytics module instantiates `BetaAnalyticsDataClient` from `@google-analytics/data` with an `OAuth2Client` configured to use the refresh token:

```javascript
// api/_lib/ga4.js
import { BetaAnalyticsDataClient } from '@google-analytics/data';
import { OAuth2Client } from 'google-auth-library';

const auth = new OAuth2Client({
  clientId: process.env.GOOGLE_ANALYTICS_CLIENT_ID,
  clientSecret: process.env.GOOGLE_ANALYTICS_CLIENT_SECRET,
});
auth.setCredentials({ refresh_token: process.env.GOOGLE_ANALYTICS_REFRESH_TOKEN });

export const analyticsClient = new BetaAnalyticsDataClient({ auth });

export async function runReport() {
  const [response] = await analyticsClient.runReport({
    property: `properties/${process.env.GA4_PROPERTY_ID}`,
    dimensions: [{ name: 'date' }],
    metrics: [{ name: 'activeUsers' }],
    dateRanges: [{ startDate: '30daysAgo', endDate: 'today' }],
  });
  return response;
}

```

This pattern enables secure, server-side GA4 reporting without exposing credentials to the browser.

### Frontend Integration ([`src/supabaseClient.js`](https://github.com/freestylefly/awesome-gpt-image-2/blob/main/src/supabaseClient.js))

The frontend initializes the Supabase client using the public anon key. When a user clicks “Sign in with Google,” the application calls:

```javascript
supabase.auth.signIn({ provider: 'google' })

```

Supabase redirects to Google’s consent screen, then back to the application with an auth code. Supabase exchanges this for a session JWT, which the frontend stores in `localStorage` and attaches to subsequent API requests via the `Authorization` header.

### Database Schema

The migration file [`supabase/migrations/20260512090000_google_account_center.sql`](https://github.com/freestylefly/awesome-gpt-image-2/blob/main/supabase/migrations/20260512090000_google_account_center.sql) defines the database tables and RPCs used by the admin dashboard to manage Google account associations. Run this migration in your Supabase SQL editor to enable the complete feature set.

## Local Development Workflow

To test the integration locally:

1. Copy the environment template:

```bash
cp .env.example .env.local

```

2. Fill in all variables, including the refresh token obtained from `npm run ga4:oauth`

3. Start the development server:

```bash
npm run dev

```

4. Navigate to `http://localhost:5173` and test the Google sign-in flow. The browser console will display the Supabase session and JWT for debugging API calls.

## Summary

- **Supabase Auth** with the Google provider handles user authentication, issuing JWTs stored in the browser
- **Vercel API routes** ([`api/_lib/supabase.js`](https://github.com/freestylefly/awesome-gpt-image-2/blob/main/api/_lib/supabase.js)) validate these JWTs server-side using the `SUPABASE_SERVICE_ROLE_KEY`
- **GA4 integration** ([`api/_lib/ga4.js`](https://github.com/freestylefly/awesome-gpt-image-2/blob/main/api/_lib/ga4.js)) uses `BetaAnalyticsDataClient` with OAuth 2.0 credentials stored exclusively in Vercel environment variables
- **Helper script** (`scripts/google-analytics-oauth.mjs`) automates the one-time OAuth flow to obtain the `GOOGLE_ANALYTICS_REFRESH_TOKEN`
- **Security** is maintained by keeping all service account credentials server-side and never exposing them to the React frontend

## Frequently Asked Questions

### How do I obtain the GA4 refresh token for Vercel?

Run the provided helper script `npm run ga4:oauth` locally. This script initiates an OAuth 2.0 flow, requests the `analytics.readonly` scope, and outputs a refresh token. Store this token as `GOOGLE_ANALYTICS_REFRESH_TOKEN` in your Vercel environment variables. The token is long-lived and allows the server to query GA4 data without user intervention.

### Can I use email/password authentication alongside Google OAuth?

According to the repository configuration (README lines 42-44), the application specifically disables the Email provider to enforce Google-only sign-in. If you need multiple providers, you would need to modify the Supabase Auth settings in your dashboard and adjust the frontend logic in [`src/supabaseClient.js`](https://github.com/freestylefly/awesome-gpt-image-2/blob/main/src/supabaseClient.js) accordingly.

### Why does the API use `SUPABASE_SERVICE_ROLE_KEY` instead of the anon key?

The `SUPABASE_SERVICE_ROLE_KEY` bypasses Row Level Security (RLS) policies, allowing Vercel serverless functions to perform administrative tasks like verifying JWTs against the `auth.users` table or accessing sensitive GA4 data. The anon key (`VITE_SUPABASE_ANON_KEY`) is safe for client-side use but lacks the privileges needed for server-side authentication validation and analytics reporting.

### How does the frontend send the authentication token to API routes?

After a successful Google sign-in, Supabase stores the JWT in the browser. The frontend attaches this token to API requests in the `Authorization: Bearer <token>` header. The server-side code in [`api/_lib/supabase.js`](https://github.com/freestylefly/awesome-gpt-image-2/blob/main/api/_lib/supabase.js) then validates this token against Supabase to confirm the user’s identity before processing the request.