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

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) 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:

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)

Vercel API routes validate incoming JWTs using the server-side Supabase client. The implementation in api/_lib/supabase.js creates a client with the service role key to verify tokens against the auth.users table:

// 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)

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

// 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)

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

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 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:
cp .env.example .env.local
  1. Fill in all variables, including the refresh token obtained from npm run ga4:oauth

  2. Start the development server:

npm run dev
  1. 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) validate these JWTs server-side using the SUPABASE_SERVICE_ROLE_KEY
  • GA4 integration (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 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 then validates this token against Supabase to confirm the user’s identity before processing the request.

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 →