# How GA4 OAuth Setup Works with the `npm run ga4:oauth` Script in awesome-gpt-image-2

> Learn how the npm run ga4:oauth script automates Google Analytics 4 OAuth 2.0 setup. Generate long-lived refresh tokens for seamless GA4 data access.

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

---

**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`](https://github.com/freestylefly/awesome-gpt-image-2/blob/main/src/_lib/ga4.js) via [`api/admin/metrics.js`](https://github.com/freestylefly/awesome-gpt-image-2/blob/main/api/admin/metrics.js) |

## Running the GA4 OAuth Script

Execute the npm script to start the authentication flow:

```bash
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:

```bash
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:

```javascript
// 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_TOKEN` as a **Sensitive** environment variable
- Add `VITE_GA_MEASUREMENT_ID=G-XXXXXXXXXX`
- Add `GA4_PROPERTY_ID=123456789`

**For local development:**

```bash

# .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`](https://github.com/freestylefly/awesome-gpt-image-2/blob/main/src/main.jsx) lines 584-589):

```javascript
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`](https://github.com/freestylefly/awesome-gpt-image-2/blob/main/api/admin/metrics.js)):

```javascript
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`](https://github.com/freestylefly/awesome-gpt-image-2/blob/main/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](https://developers.google.com/analytics/devguides/reporting/data/v1) for real-time and historical metrics.

## Why This OAuth Approach Matters

This setup provides **three critical security benefits**:

1. **No client-side secrets** — The refresh token never reaches the browser; all GA4 API calls happen server-side
2. **Long-lived authorization** — One OAuth flow generates a refresh token valid until explicitly revoked
3. **Minimal permission scope** — Only `analytics.readonly` is 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:oauth`** script in `awesome-gpt-image-2` automates 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_TOKEN`** enables server-side GA4 data queries without exposing credentials
- Runtime code in **[`src/_lib/ga4.js`](https://github.com/freestylefly/awesome-gpt-image-2/blob/main/src/_lib/ga4.js)** manages token refresh and API calls, accessed via **[`api/admin/metrics.js`](https://github.com/freestylefly/awesome-gpt-image-2/blob/main/api/admin/metrics.js)**
- The flow requires **`GOOGLE_CLIENT_ID`** and **`GOOGLE_CLIENT_SECRET`** environment 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`](https://github.com/freestylefly/awesome-gpt-image-2/blob/main/src/_lib/ga4.js)** (imported by [`api/admin/metrics.js`](https://github.com/freestylefly/awesome-gpt-image-2/blob/main/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.