Google Ads refresh token expired

Google Ads Refresh Token Expired: Fix and Prevent

4 min read • install
Admaxxer is a DTC analytics platform with built-in Meta + Google ad ops. When a Google Ads refresh token expires, Admaxxer can no longer sync spend, campaigns, or conversions for that account and your dashboards start showing stale numbers. TL;DR: reconnect Google Ads from the connection card in Admaxxer to mint a new refresh token, then make sure the daily token-heartbeat job is running so the next expiry is caught 7 days in advance instead of after the fact. ## Symptoms - Google Ads spend on your Admaxxer dashboard has not updated in 24+ hours. - The connection card shows a red status or an "Invalid refresh token" error. - Server logs contain `invalid_grant` errors from Google's OAuth endpoint. - `cost_micros` totals stop at a specific timestamp and flat-line afterwards. - Blended MER looks artificially better because Google spend is missing from the denominator. ## Root cause Google OAuth refresh tokens do not last forever. The two most common reasons they stop working: 1. **Inactivity**: if the refresh token is unused for 6 months, Google revokes it. 2. **Unverified app**: if your Google Cloud OAuth consent screen is still in "Testing" status (not verified), refresh tokens are capped to about 7 days for any user who is not on the test-users list. Other revocation triggers: the user changed their Google password, manually revoked Admaxxer from their Google account, or exceeded Google's active refresh-token limit per user per client ID (older tokens get evicted). A secondary gotcha is storage corruption — refresh tokens are stored AES-256-GCM encrypted, so a broken `ENCRYPTION_KEY` rotation can make a valid token decrypt incorrectly and look invalid. ## Fix ### Step 1: Open the Google Ads connection card Go to Admaxxer -> Connections -> Google Ads. You should see the broken connection flagged with a red badge. ### Step 2: Click Reconnect This sends you through Google's OAuth consent flow. Make sure you sign in with the same Google account that owns the Google Ads manager (MCC) you want to pull data from, otherwise Admaxxer will attach a token that cannot read the target customer id. ### Step 3: Request offline access The OAuth flow Admaxxer initiates already includes `access_type=offline` and `prompt=consent`. Do not remove the consent prompt — without it Google will not re-issue a refresh token for users who previously consented. ### Step 4: Verify the scopes You must grant the `https://www.googleapis.com/auth/adwords` scope. Declining this scope means the OAuth token will be minted but every GAQL query will return 403. ### Step 5: Confirm the new token is stored After the callback, Admaxxer will show the connection as green and trigger a backfill sync. The refresh token is encrypted at rest with AES-256-GCM before being written to `ad_platform_connections`. ## Verify the fix - The Google Ads card in Admaxxer shows a green "Connected" status with the most recent sync timestamp. - Ad spend in your Admaxxer dashboard updates within a few minutes of the reconnect. - A test GAQL query (Admaxxer runs one automatically on reconnect) returns a non-zero row count for the last 7 days. - Server logs should show a successful token refresh, not `invalid_grant` or `unauthorized_client`. ## Prevent it next time - **Verify your OAuth app.** In Google Cloud Console, submit the OAuth consent screen for verification. Once verified, refresh tokens are not capped at 7 days. - **Run a daily heartbeat job.** Admaxxer runs a cron that checks every Google Ads refresh token daily and alerts when the token would not survive the next 7 days. If you see "expiring in <7d" in the connection card, reconnect proactively rather than waiting for the failure. - **Monitor your Google Cloud project.** Keep `developer_token` and OAuth client id in sync with what Admaxxer stores; rotating the client id without updating Admaxxer will invalidate every refresh token bound to the old client id. - **Rotate `ENCRYPTION_KEY` carefully.** If you rotate the platform encryption key, you must re-encrypt all stored tokens in the same deploy; otherwise every connection will look expired on the next sync. ## Related guides - [Meta long-lived token setup and rotation](/guides/meta-long-lived-token-rotation) - [Verify revenue attribution after install](/guides/verify-revenue-attribution-after-install) - [Google Ads install guide](/documentation/install/google-ads) ## FAQs **Q: How long do Google Ads refresh tokens last?** A: Indefinitely for verified OAuth apps as long as they are used at least every 6 months. For unverified / testing apps, refresh tokens for non-test users expire after about 7 days. **Q: Do I lose historical data when I reconnect?** A: No. Admaxxer re-hydrates historical data on the next sync. Your previously ingested campaign and spend rows stay in place. **Q: Can I use a service account instead of OAuth?** A: The Google Ads API supports service accounts, but only when your Google Workspace admin delegates domain-wide access. Admaxxer's default flow uses user-level OAuth because most DTC brands do not manage Google Ads inside a Workspace with delegated admin.

Frequently Asked Questions

How long do Google Ads refresh tokens last?

Indefinitely for verified OAuth apps as long as they are used at least every 6 months. For unverified/testing apps, refresh tokens for non-test users expire after about 7 days.

Do I lose historical data when I reconnect?

No. Admaxxer re-hydrates historical data on the next sync. Your previously ingested campaign and spend rows stay in place.

Can I use a service account instead of OAuth?

The Google Ads API supports service accounts, but only when your Google Workspace admin delegates domain-wide access. Admaxxer's default flow is user-level OAuth.

Put This Knowledge Into Action

Bring Meta and Google ads into one self-hosted workspace.

Get Started Free