How GA4 OAuth Setup Works with the `npm run ga4:oauth` Script in awesome-gpt-image-2
The npm run ga4:oauth command runs a Node.js script that automates Google's OAuth 2.0 Authorization Code flow to generate a long-lived refresh token for Google Analytics 4 data access.
The awesome-gpt-image-2 repository implements a complete GA4 OAuth automation that handles everything from consent URL generation to token exchange in a single command. This setup allows the application to query GA4 traffic data server-side without exposing credentials to the client.
What the GA4 OAuth Script Does
The OAuth flow implemented in scripts/google-analytics-oauth.mjs follows the standard Google OAuth 2.0 pattern with six distinct phases:
| Step | Action | Implementation Location |
|---|---|---|
| 1 | Generates OAuth consent URL with analytics.readonly scope |
scripts/google-analytics-oauth.mjs |
| 2 | Prompts user to authenticate and authorize in browser | Terminal output from same script |
| 3 | Captures authorization code via localhost callback server | Port 8080 handler in same script |
| 4 | Exchanges code for access_token and refresh_token |
POST to oauth2.googleapis.com/token |
| 5 | Outputs refresh token for environment configuration | Terminal output |
| 6 | Runtime code uses token to query GA4 Reporting API | src/_lib/ga4.js via api/admin/metrics.js |
Running the GA4 OAuth Script
Execute the npm script to start the authentication flow:
npm run ga4:oauth
This prints a URL similar to:
https://accounts.google.com/o/oauth2/auth?
client_id=xxx.apps.googleusercontent.com
&redirect_uri=http://localhost:8080/oauth2callback
&scope=https://www.googleapis.com/auth/analytics.readonly
&response_type=code
&access_type=offline
The script requires these environment variables in your .env file:
GOOGLE_CLIENT_ID=xxx.apps.googleusercontent.com
GOOGLE_CLIENT_SECRET=xxx
Without these values, the script cannot construct the OAuth request or authenticate with Google's token endpoint.
How the Callback Server Captures the Authorization Code
Once you open the URL and grant permission, Google redirects to http://localhost:8080/oauth2callback?code=AUTH_CODE. The script's embedded HTTP server handles this request:
// From scripts/google-analytics-oauth.mjs
const server = createServer(async (req, res) => {
const url = new URL(req.url, `http://${req.headers.host}`);
const code = url.searchParams.get('code');
// Exchange code for tokens
const tokenResponse = await fetch('https://oauth2.googleapis.com/token', {
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: new URLSearchParams({
code,
client_id: process.env.GOOGLE_CLIENT_ID,
client_secret: process.env.GOOGLE_CLIENT_SECRET,
redirect_uri: 'http://localhost:8080/oauth2callback',
grant_type: 'authorization_code',
}),
});
const tokens = await tokenResponse.json();
console.log('GOOGLE_ANALYTICS_REFRESH_TOKEN=' + tokens.refresh_token);
res.end('Authorization successful. Return to terminal.');
server.close();
});
server.listen(8080);
The server automatically shuts down after capturing the code, making this a one-time setup process.
Configuring the Refresh Token in Your Environment
Copy the printed refresh_token and add it to your deployment environment:
For Vercel (production):
- Add
GOOGLE_ANALYTICS_REFRESH_TOKENas a Sensitive environment variable - Add
VITE_GA_MEASUREMENT_ID=G-XXXXXXXXXX - Add
GA4_PROPERTY_ID=123456789
For local development:
# .env.local
GOOGLE_ANALYTICS_REFRESH_TOKEN=1//0gX...
VITE_GA_MEASUREMENT_ID=G-XXXXXXXXXX
GA4_PROPERTY_ID=123456789
How the Application Uses the GA4 Token at Runtime
The refresh token enables server-side GA4 data access through a chain of modules:
Frontend script injection (src/main.jsx lines 584-589):
const existingScript = document.querySelector(`script[data-ga4="${gaMeasurementId}"]`);
if (!existingScript) {
const script = document.createElement('script');
script.async = true;
script.src = `https://www.googletagmanager.com/gtag/js?id=${gaMeasurementId}`;
script.dataset.ga4 = gaMeasurementId;
document.head.appendChild(script);
}
Admin metrics API (api/admin/metrics.js):
import { getGa4Traffic, isGa4Configured } from '../_lib/ga4.js';
// getGa4Traffic uses the refresh token to obtain a fresh access token
// and queries the GA4 Reporting API for traffic metrics
The src/_lib/ga4.js module handles the token refresh logic transparently—exchanging the stored refresh token for short-lived access tokens as needed, then querying the GA4 Data API for real-time and historical metrics.
Why This OAuth Approach Matters
This setup provides three critical security benefits:
- No client-side secrets — The refresh token never reaches the browser; all GA4 API calls happen server-side
- Long-lived authorization — One OAuth flow generates a refresh token valid until explicitly revoked
- Minimal permission scope — Only
analytics.readonlyis requested, following principle of least privilege
The npm run ga4:oauth command encapsulates complexity that would otherwise require manual HTTP requests or external tooling.
Summary
- The
npm run ga4:oauthscript inawesome-gpt-image-2automates the complete GA4 OAuth 2.0 flow - It generates consent URLs, runs a temporary localhost server on port 8080, and exchanges codes for refresh tokens
- The resulting
GOOGLE_ANALYTICS_REFRESH_TOKENenables server-side GA4 data queries without exposing credentials - Runtime code in
src/_lib/ga4.jsmanages token refresh and API calls, accessed viaapi/admin/metrics.js - The flow requires
GOOGLE_CLIENT_IDandGOOGLE_CLIENT_SECRETenvironment variables to function
Frequently Asked Questions
What happens if the localhost:8080 port is already in use?
The script will fail to bind and throw an EADDRINUSE error. Either free the port or modify the redirect_uri constant in scripts/google-analytics-oauth.mjs to use an alternative port, updating both the script and your Google Cloud Console redirect URI configuration.
Can I reuse the same refresh token across multiple deployments?
Yes. The refresh token is tied to your Google account and OAuth client, not to a specific deployment. You can use the same GOOGLE_ANALYTICS_REFRESH_TOKEN value in Vercel production, preview environments, and local development—provided all use the same GOOGLE_CLIENT_ID.
Why does the script request offline access type?
The access_type=offline parameter (included in the consent URL) is required for Google to return a refresh_token. Without this, the authorization would only yield a short-lived access token, forcing you to repeat the OAuth flow repeatedly instead of storing persistent access.
Where is the GA4 data actually fetched in the codebase?
The low-level GA4 API integration lives in src/_lib/ga4.js (imported by api/admin/metrics.js). This module uses the refresh token to call Google's token endpoint for fresh access tokens, then queries the GA4 Data API for metrics like active users and page views.
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 →