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 withanalytics.readonlyscope 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:
- Navigate to your Supabase dashboard → Authentication → Providers → Google
- Create a Google OAuth Web Client in Google Cloud Console
- Add authorized redirect URIs:
http://localhost:8080/oauth2callback(for local development) and your production Vercel domain - 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 URLVITE_SUPABASE_ANON_KEY– Public Supabase client keySUPABASE_SERVICE_ROLE_KEY– Private service role key for server-side operationsVITE_GA_MEASUREMENT_ID– GA4 measurement ID (e.g.,G-XXXXXXX)GA4_PROPERTY_ID– Numeric GA4 property identifierGOOGLE_ANALYTICS_CLIENT_ID– OAuth 2.0 Client IDGOOGLE_ANALYTICS_CLIENT_SECRET– OAuth 2.0 Client SecretGOOGLE_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:
- Copy the environment template:
cp .env.example .env.local
-
Fill in all variables, including the refresh token obtained from
npm run ga4:oauth -
Start the development server:
npm run dev
- Navigate to
http://localhost:5173and 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 theSUPABASE_SERVICE_ROLE_KEY - GA4 integration (
api/_lib/ga4.js) usesBetaAnalyticsDataClientwith 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 theGOOGLE_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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →