GA4 OAuth Flow for Analytics Readonly Permission: Complete Implementation Guide
The Awesome‑GPT‑Image‑2 repository implements a standalone Node.js OAuth helper in scripts/google-analytics-oauth.mjs that obtains a refresh token with analytics.readonly scope for server-side Google Analytics 4 data access.
This guide explains how the GA4 OAuth flow works in the freestylefly/awesome-gpt-image-2 repository, walking you through the exact authentication process used to securely read analytics data without exposing credentials to the client.
How the GA4 OAuth Flow Works
The repository's OAuth implementation follows Google's standard offline access pattern, forcing a consent screen to guarantee a refresh token is returned. The entire flow is encapsulated in a single CLI script.
Step 1: Load Client Credentials
The helper first loads your Google Cloud OAuth credentials from environment variables. In scripts/google-analytics-oauth.mjs lines 50-52, the script reads:
GOOGLE_ANALYTICS_CLIENT_IDGOOGLE_ANALYTICS_CLIENT_SECRET
// From scripts/google-analytics-oauth.mjs
const clientId = process.env.GOOGLE_ANALYTICS_CLIENT_ID;
const clientSecret = process.env.GOOGLE_ANALYTICS_CLIENT_SECRET;
const redirectUri = process.env.GOOGLE_ANALYTICS_REDIRECT_URI || 'http://localhost:8080/oauth2callback';
Step 2: Build the Authorization URL
Using google-auth-library's OAuth2Client, the script constructs the authorization URL at lines 59-64. Critical parameters include:
access_type: 'offline'— Required to receive a refresh tokenprompt: 'consent'— Forces the consent screen even if previously authorizedscope: 'https://www.googleapis.com/auth/analytics.readonly'— Read-only GA4 access
const authUrl = oauth2Client.generateAuthUrl({
access_type: 'offline',
prompt: 'consent',
scope: ['https://www.googleapis.com/auth/analytics.readonly'],
});
Step 3: Exchange Authorization Code for Tokens
After the user grants consent and Google redirects to your localhost callback, you provide the code parameter to the script (lines 70-77). The script exchanges this for tokens at lines 79-84 using oauth2Client.getToken(code).
The response contains both an access token and the critical refresh token needed for long-term server-side access.
Required Environment Variables
Configure these variables before running the OAuth helper, as documented in .env.example lines 30-34 and the README section 🔐 Website Auth & Generation:
| Variable | Required | Purpose |
|---|---|---|
GOOGLE_ANALYTICS_CLIENT_ID |
Yes | OAuth client ID from Google Cloud Console |
GOOGLE_ANALYTICS_CLIENT_SECRET |
Yes | OAuth client secret paired with the client ID |
GOOGLE_ANALYTICS_REDIRECT_URI |
No | Custom callback URI; defaults to http://localhost:8080/oauth2callback |
GOOGLE_ANALYTICS_REFRESH_TOKEN |
Output | Generated by the flow — add to Vercel as a Sensitive environment variable |
Running the OAuth Helper
Generate Your Refresh Token
# Run the interactive OAuth flow
npm run ga4:oauth
The script outputs:
Authorize this app by visiting this url:
https://accounts.google.com/o/oauth2/v2/auth?access_type=offline...
Paste callback URL or code:
Complete the Flow
- Open the printed URL in your browser
- Sign in with a Google account that has read access to your GA4 property
- Click Allow on the consent screen
- Copy the full callback URL (e.g.,
http://localhost:8080/oauth2callback?code=4/0AY0e-g5...) - Paste it into the terminal prompt
The script extracts the refresh token and outputs:
Add this to Vercel Environment Variables as a Sensitive value:
GOOGLE_ANALYTICS_REFRESH_TOKEN=1//0gkU4B...
Using the Refresh Token in Production
The GOOGLE_ANALYTICS_REFRESH_TOKEN enables server-side code to access GA4 data without user interaction. The repository's package.json lists @google-analytics/data as a dependency (lines 22-23) for making API calls.
Example server-side usage pattern:
import { BetaAnalyticsDataClient } from '@google-analytics/data';
const analyticsDataClient = new BetaAnalyticsDataClient({
credentials: {
client_id: process.env.GOOGLE_ANALYTICS_CLIENT_ID,
client_secret: process.env.GOOGLE_ANALYTICS_CLIENT_SECRET,
refresh_token: process.env.GOOGLE_ANALYTICS_REFRESH_TOKEN,
},
});
async function getPageViews() {
const [response] = await analyticsDataClient.runReport({
property: `properties/${process.env.GA4_PROPERTY_ID}`,
dateRanges: [{ startDate: '30daysAgo', endDate: 'today' }],
dimensions: [{ name: 'pagePath' }],
metrics: [{ name: 'screenPageViews' }],
});
return response;
}
The refresh token automatically generates short-lived access tokens for each API request.
Key Implementation Files
| File | Lines | Purpose |
|---|---|---|
scripts/google-analytics-oauth.mjs |
50-87 | Complete OAuth flow implementation |
.env.example |
30-34 | Environment variable template |
README.md |
🔐 Website Auth & Generation section | High-level authentication documentation |
package.json |
22-23 | google-auth-library and @google-analytics/data dependencies |
Summary
- The GA4 OAuth flow in
awesome-gpt-image-2is implemented as a CLI helper atscripts/google-analytics-oauth.mjs - Offline access with forced consent guarantees a refresh token is returned for server-side use
- The
analytics.readonlyscope provides read-only access to GA4 properties - Environment variables
GOOGLE_ANALYTICS_CLIENT_IDandGOOGLE_ANALYTICS_CLIENT_SECRETare required inputs - The output refresh token must be stored as a Sensitive Vercel environment variable named
GOOGLE_ANALYTICS_REFRESH_TOKEN - The
@google-analytics/dataclient consumes this token to query analytics without exposing credentials to browsers
Frequently Asked Questions
What OAuth scope does the repository request for GA4 access?
The repository requests https://www.googleapis.com/auth/analytics.readonly — the read-only scope for Google Analytics 4. This scope allows fetching reports and dimensions without permission to modify property settings or data. The scope is hardcoded in scripts/google-analytics-oauth.mjs lines 62-63.
Why does the script use prompt: 'consent'?
The prompt: 'consent' parameter forces Google to display the consent screen even if the user previously authorized the application. This is essential for obtaining a refresh token every time, because Google only returns refresh tokens on the first authorization unless explicitly re-prompted. Without this parameter, repeat runs might fail to capture the refresh token needed for long-term server access.
Can I use a service account instead of OAuth?
The repository's implementation is designed for OAuth 2.0 with user credentials, not service accounts. However, the @google-analytics/data client supports service account authentication using client_email and private_key instead of a refresh token. To migrate, create a service account in Google Cloud Console, grant it GA4 property access, and replace the credentials object in your server code accordingly.
Where do I store the refresh token securely?
Store GOOGLE_ANALYTICS_REFRESH_TOKEN as a Sensitive environment variable in your deployment platform. In Vercel, navigate to Project Settings → Environment Variables, add the variable, and mark it as Sensitive to prevent exposure in logs or to team members without proper permissions. Never commit this token to version control.
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 →