Gong OAuth refresh token invalid_grant — What it means & how to fix it
How to diagnose and fix Gong refresh token invalid_grant errors
If your product integrates with Gong via OAuth 2.0, you’ll eventually see a refresh fail. It often shows up as invalid_grant, and it’s the kind of failure that doesn’t degrade gracefully: sync jobs stop, dashboards go stale, and customers ask “why did Gong disconnect?”
This guide shows you how to recognize Gong refresh-token failures, what’s usually behind them (hint: Gong refresh tokens are single-use), and how to fix and prevent the issue in production. For broader context, see API Auth Is Deeper Than It Looks and Why is OAuth still hard in 2025?.
Spot the error
When your backend exchanges a refresh token for a new access token against Gong:
- Token endpoint:
https://app.gong.io/oauth2/generate-customer-token - Often HTTP status:
400 - Common OAuth error:
invalid_grant
Per Gong’s OAuth docs, refresh happens via the generate-customer-token endpoint with grant_type=refresh_token and HTTP Basic auth (using your OAuth app’s client_id and client_secret).
Example response payload (shape):
Gong OAuth error response
📋
{
"error": "invalid_grant",
"error_description": "Token has been expired or revoked."
}
You may also see error text like “Refresh token code is invalid”. Either way, the meaning is consistent: the refresh token you’re sending can’t be used to mint a new access token. Retrying that same refresh token won’t help.
Why did Gong reject the refresh token?
With Gong, invalid_grant is usually not “random OAuth flakiness”. It’s a predictable result of how Gong refresh tokens work, plus how most integration backends are deployed (multiple workers, retries, and race conditions).
Most common: Gong refresh tokens are single-use (rotation every refresh)
Gong refresh tokens are one-time tokens. Each successful refresh returns a new access_token and a new refresh_token, and the previous refresh token is immediately invalidated.
If your system keeps refreshing with the older refresh token (or you lose the newly returned one), the next refresh fails with invalid_grant.
Refresh-token concurrency (race conditions)
Single-use refresh tokens make concurrency bugs much easier to trigger:
- Worker A refreshes and stores a new refresh token
- Worker B refreshes at the same time with the old refresh token
- Result: one refresh wins; the other gets
invalid_grant(and may overwrite stored state)
If you’re running multiple workers, serverless jobs, or retries, this is the most common root cause. If you want the deeper mechanics and patterns, see How to handle concurrency with OAuth token refreshes.
The customer revoked access / disconnected the app
If a customer disconnects the integration (or an admin revokes access/changes the OAuth app), your stored tokens won’t refresh anymore. In that case, invalid_grant is terminal and you need a new authorization.
Wrong OAuth app credentials
Gong’s OAuth token calls use HTTP Basic authentication with your client_id and client_secret. If you refresh with the wrong credentials (staging vs production, rotated secret not deployed, wrong app), Gong can reject the request.
Mismatched OAuth assumptions (Gong isn’t user-level OAuth)
Gong notes it doesn’t support user-level OAuth; authorization happens once at a global level. If your internal model assumes per-user refresh tokens and tries to refresh them independently, you’ll end up with brittle behavior and avoidable failures.
How to fix it
1) Persist the newest refresh token every time
Treat “store the new refresh token” as mandatory after every successful refresh. Use it for the next refresh. Discard the old one.
2) Make refresh single-flight per connection (lock it)
If your system can refresh the same connection from more than one process, you need a lock:
- Only one refresh request in flight per connection
- Everyone else waits and reuses the updated token set
- Tokens are persisted atomically
3) Verify you’re using Gong’s documented OAuth endpoints
From Gong’s docs:
- Authorize:
https://app.gong.io/oauth2/authorize - Token + refresh:
https://app.gong.io/oauth2/generate-customer-token
Also note that Gong’s examples pass parameters (like grant_type and refresh_token) as query parameters to generate-customer-token, authenticated via HTTP Basic.
4) If it’s still failing: treat invalid_grant as terminal and re-auth
After you’ve ruled out stale refresh tokens, concurrency, and credential mismatch:
- Stop retry storms
- Mark the connection as “needs re-auth”
- Send the customer through the OAuth authorization flow again
How to prevent Gong refresh token issues
Use this checklist to reduce “why did my Gong API integration break?” tickets:
- Assume refresh tokens rotate on every refresh
Always persist the latest refresh token returned by Gong. - Single-flight refresh
One refresh per connection at a time. - Atomic token writes
Store(access_token, refresh_token, expires_at)together. - Clear reconnect UX
A clean “Reconnect Gong” flow prevents support loops and keeps customers unblocked.
Skip the headache, let Nango refresh for you
Nango's open-source API auth offers:
- 600+ pre-built OAuth flows, including full support for all Gong APIs
- Automatic OAuth access token refreshing and rotation
- Webhooks when a refresh token is revoked, so you can warn the user instantly
- Built-in error handling for all OAuth edge cases
If you're building a Gong API integration and you don’t want to build distributed locking, token rotation persistence, and re-auth flows yourself, Nango can run the refresh pipeline for you.
Focus on product features and let Nango handle the token lifecycle.

.png)



