Google OAuth Refresh Token: Expiration, 7-Day Limit & Lifetime Explained (2026)

Google OAuth - Developer Guide

Google OAuth Refresh Token: Expiration, 7-Day Limit & Lifetime Explained (2026)

Google OAuth refresh tokens don't last forever. Understand every expiration condition - from the 7-day testing trap to the 6-month inactivity rule - and learn how to keep your Gmail API integration alive in production.

refresh_token.py
import requests # Exchange refresh token for new access token response = requests.post( "https://oauth2.googleapis.com/token", data={ "client_id": "YOUR_CLIENT_ID", "client_secret": "YOUR_SECRET", "refresh_token": "1//0g...", "grant_type": "refresh_token" } ) token = response.json()["access_token"]
200 OK - access_token valid for 3600s
Data Handling Note
How Unipile handles OAuth tokens and user data

Unipile does not store OAuth tokens in a parallel archive or create independent data copies outside the authenticated session. Token storage and refresh operations are scoped exclusively to the session of each authenticated user who has explicitly granted access. No token data is shared across accounts or retained beyond the authorization scope defined by the user.

How Unipile Operates
Unipile as an independent technical intermediary

Unipile acts as an independent technical intermediary, performing Gmail API and OAuth token operations on behalf of each authenticated user who has individually authorized access. Unipile is not affiliated with, endorsed by, or sponsored by Google. No shared credentials are used. Each integration relies on the user's own Google OAuth consent, issued through their own Google Cloud project or via Unipile's CASA Tier 2 certified OAuth flow.

Platform Limits & Responsible Use
Rate limits and quota management

Unipile relays Google API rate limits and quota restrictions as defined by Google's policies. Request cadence, volume decisions, and usage patterns remain a customer-side decision. Developers are responsible for ensuring their integration complies with Google's Terms of Service, including OAuth token handling policies and data access scopes. Unipile provides infrastructure - policy compliance is the responsibility of each developer.

Definition

What is a Google OAuth refresh token?

Before diving into expiration rules, it helps to understand exactly what a Google OAuth refresh token is, what it does, and how it differs from an access token in the Google OAuth2 flow.

Quick Definition

A Google OAuth refresh token is a long-lived credential issued by Google's authorization server that allows your application to obtain new access tokens without requiring the user to re-authenticate. Unlike access tokens (which expire after 3,600 seconds), a google oauth refresh token persists across sessions - subject to specific expiration conditions - and is issued only when the access_type=offline parameter is included in the authorization request.

01
User grants consent

The authenticated user approves your app's requested scopes on Google's consent screen. With access_type=offline, Google issues both an access token and a refresh token.

02
Access token expires (1h)

Access tokens have a fixed TTL of 3,600 seconds. Once expired, any API call returns a 401 Unauthorized error. Your app must exchange the refresh token for a new access token.

03
Refresh token exchange

A POST to https://oauth2.googleapis.com/token with grant_type=refresh_token returns a new access token. The google oauth refresh token itself remains valid (unless one of the 6 expiration conditions fires).

Access token vs. Google OAuth2 refresh token at a glance
Token type Access token - short-lived bearer token
Token type Refresh token - long-lived credential
Lifetime 3,600 seconds (1 hour), always
Lifetime Indefinite in production (see 6 conditions)
Required param Issued automatically with every consent
Required param access_type=offline must be set
Format prefix Short JWT starting with ya29.
Format prefix Long opaque string starting with 1//
Expiration Rules

Do Google refresh tokens expire? The 6 conditions

Yes, a Google OAuth refresh token can expire - but only under specific conditions. Understanding every case is critical for any Gmail API integration that needs to run unattended. Here are all six Google OAuth refresh token expiration scenarios you must handle in production.

# Condition When it fires Severity Fix
1 App in testing mode - 7-day limit OAuth consent screen is "Testing" and app is not verified by Google Critical Publish the app or use an internal Workspace app
2 6 months of inactivity Token has not been used to obtain an access token for 6 months Medium Implement keep-alive pings; use token at least every 6 months
3 User changes Google password Only affects tokens with Gmail or sensitive mail scopes Medium Re-initiate OAuth flow; prompt re-authorization
4 50 refresh tokens per client-user pair User authorizes your app more than 50 times; oldest tokens silently revoked Medium Store tokens server-side; never re-prompt unless token is invalid
5 User explicitly revokes access User visits Google Account settings and removes your app Expected Catch invalid_grant; remove stored token; prompt re-authorization
6 Sensitive/restricted scope - app not verified App requests restricted scopes without passing Google verification Critical Complete Google OAuth verification or scope down to non-sensitive scopes

Key insight: The 7-day limit (condition 1) is the most common cause of broken integrations during development. It only applies when your app's OAuth consent screen status is "Testing" and the app has NOT been submitted for Google verification. The Google OAuth verification process is the permanent fix - but it takes time. See section 3 for faster workarounds.

Critical Scenario

The 7-day testing trap: why it happens, how to escape

The Google OAuth refresh token 7-day expiration is the most disruptive issue developers face during integration. It catches teams off guard: everything works in development, tokens stop refreshing exactly 7 days later, and the error response often appears days after the user authorized the app.

Why does the Google OAuth refresh token expire after 7 days?

When an app's OAuth consent screen status is set to "Testing" in Google Cloud Console, Google treats it as an unverified application. To protect users, Google automatically expires all refresh tokens issued by unverified apps after exactly 7 days. This policy is documented in Google's OAuth 2.0 documentation and applies regardless of how many times the user has authorized the app. The cap also applies to the 100 test user limit for apps in testing mode. Once a google oauth refresh token expires under this rule, any attempt to use it returns invalid_grant.

3 fixes: move from testing to production
01
Permanent Fix
Publish your app and complete Google verification

Change your app's OAuth consent screen status from "Testing" to "In Production" in Google Cloud Console. For apps requesting sensitive or restricted Gmail scopes, you must complete the full Google OAuth app verification process, including a security audit. Once published, google oauth refresh token lifetime becomes indefinite (subject to the remaining 5 conditions).

02
Dev/Internal
Use an internal Google Workspace app

If your app is only used within a Google Workspace organization, set the OAuth consent screen user type to "Internal". Internal apps are not subject to the 7-day expiration or the 100 test user cap. Tokens issued to Workspace users under internal apps do not expire based on the testing mode rule. This is the fastest path for B2B SaaS products with Google Workspace customers.

03
Fastest Path
Use Unipile's certified OAuth flow

Unipile operates as an independent technical intermediary on behalf of each authenticated user. Our OAuth flow is CASA Tier 2 certified. You can test with non-expiring tokens immediately while your own Google OAuth verification is in progress, then switch to Bring-Your-Own-Credentials (BYOC) once approved. No 7-day limit during your POC phase.

Skip the 7-day trap during your POC

Build your Gmail integration today with tokens that don't expire after 7 days. Unipile handles token refresh on the server side.

Start building
Production

Google OAuth refresh token lifetime in production

Once your app is published and verified, Google OAuth refresh token lifetime becomes effectively indefinite - but with important caveats. The two key production rules are the 50-token-per-client-user cap and the 6-month inactivity expiration.

6-month inactivity rule

A google oauth refresh token expires if it has not been used to obtain a new access token for 6 consecutive months. "Used" means a successful token refresh call - not an API call made with the resulting access token. Store refresh tokens and schedule periodic silent refreshes to keep them alive. A monthly ping to /token is sufficient.

Google OAuth refresh token expiration in Google Workspace

For Google Workspace apps with user type "Internal", there is no 7-day expiration and no verification requirement. Tokens still observe the 6-month inactivity rule and the 50-token limit per client-user pair. Workspace admins can also revoke tokens organization-wide via the Admin Console, which overrides application-level token management.

The 50 refresh tokens per client-user limit

Google allows a maximum of 50 refresh tokens per OAuth client ID + Google user account combination. If your app generates a new refresh token (by prompting the user again with prompt=consent) beyond this limit, Google silently invalidates the oldest token. This is a common source of invalid_grant errors in production when teams repeatedly re-authorize users during testing or re-onboarding flows. The fix is simple: store the refresh token server-side and never re-prompt unless the token is actually invalid.

What counts as "using" a google oauth2 refresh token:

Counts as use: POST to https://oauth2.googleapis.com/token with grant_type=refresh_token that returns a new access token

Does NOT count as use: making Gmail API calls with the current access token, even millions of them

Does NOT count as use: calling tokeninfo or introspection endpoints - only the token exchange endpoint resets the inactivity clock

Code Examples

How to refresh an access token: curl, Node.js, Python

When your access token expires, you need to exchange your Google OAuth refresh token for a new one. Here are production-ready code samples for three common environments. All three hit the same Google OAuth token endpoint.

refresh.sh
# Refresh a Google OAuth access token using curl curl -s -X POST \ "https://oauth2.googleapis.com/token" \ -H "Content-Type: application/x-www-form-urlencoded" \ -d "client_id=YOUR_CLIENT_ID" \ -d "client_secret=YOUR_CLIENT_SECRET" \ -d "refresh_token=YOUR_REFRESH_TOKEN" \ -d "grant_type=refresh_token" # Response: { "access_token": "ya29.XXX", "expires_in": 3600, "token_type": "Bearer" }
Returns new access_token valid for 3600 seconds
refresh_token.py
import requests import json def refresh_google_access_token(refresh_token: str) -> str: """Exchange a google oauth refresh token for a new access token.""" response = requests.post( "https://oauth2.googleapis.com/token", data={ "client_id": "YOUR_CLIENT_ID", "client_secret": "YOUR_CLIENT_SECRET", "refresh_token": refresh_token, "grant_type": "refresh_token", }, ) data = response.json() if "error" in data: raise ValueError(f"Token refresh failed: {data['error']} - {data.get('error_description')}") return data["access_token"]
Raises ValueError on invalid_grant - catch and re-authorize user
refreshToken.js
// Refresh a Google OAuth access token - Node.js (fetch) async function refreshGoogleAccessToken(refreshToken) { const params = new URLSearchParams({ client_id: "YOUR_CLIENT_ID", client_secret: "YOUR_CLIENT_SECRET", refresh_token: refreshToken, grant_type: "refresh_token", }); const res = await fetch("https://oauth2.googleapis.com/token", { method: "POST", headers: { "Content-Type": "application/x-www-form-urlencoded" }, body: params.toString(), }); const data = await res.json(); if (data.error) throw new Error(`${data.error}: ${data.error_description}`); return data.access_token; // valid for 3600s }
Throws on error.error === "invalid_grant" - trigger re-auth
Error Handling

invalid_grant: quick guide

When a Google OAuth refresh token is expired, revoked, or invalid, the token endpoint returns an invalid_grant error. This is the canonical sign that your google oauth refresh token is no longer usable. Here are the most common causes and their immediate fixes.

{ "error": "invalid_grant", "error_description": "Token has been expired or revoked." }
01
7-day expiration (testing mode)

App is in "Testing" status. Token expired after 7 days. Fix: publish app or switch to internal Workspace.

02
6-month inactivity

Token not used for 6 months. Fix: implement keep-alive refresh; schedule monthly token exchange.

03
50-token cap exceeded

User consented too many times; oldest token silently revoked. Fix: store tokens server-side, never re-prompt unnecessarily.

04
User revoked access

User removed your app from Google Account settings. Fix: delete stored token; display re-authorization prompt to user.

05
Password change (Gmail scopes)

User changed Google password while your app holds sensitive Gmail scopes. Fix: catch error, prompt re-authorization.

06
Wrong credentials or copy-paste error

Mismatched client_id/secret, or token was issued by a different app. Fix: verify credentials; test with the OAuth Playground.

Build your refresh flow with Unipile
Managed Solution

Managed refresh tokens with Unipile

Building and maintaining a robust Google OAuth refresh token lifecycle is non-trivial engineering work. Unipile acts as an independent technical intermediary on behalf of each authenticated user, handling token storage, refresh scheduling, and error recovery server-side - so your team ships features instead of debugging invalid_grant at 2 AM.

Token storage & auto-refresh

Unipile stores your users' refresh tokens encrypted server-side and proactively refreshes access tokens before they expire. No 401 errors reach your application.

CASA Tier 2 certified OAuth flow

Unipile's own OAuth application has passed CASA Tier 2 security assessment. During your POC, your users authorize via Unipile's verified flow - no 7-day testing limit applies.

Bring-Your-Own-Credentials (BYOC)

When your own Google OAuth verification is approved, switch to BYOC mode: your users authorize via your own verified Google app, while Unipile continues handling token refresh infrastructure.

Unified API for Gmail, Outlook, and IMAP

Unipile provides a single Gmail API abstraction layer that also covers Outlook (Microsoft 365 + Exchange Online) and IMAP - each with its own managed token lifecycle, so you never implement provider-specific refresh logic.

POC to production in 3 steps
01

POC with Unipile key: Connect your first authenticated users immediately via Unipile's CASA Tier 2 flow. No 7-day expiration. Full Gmail API access via Unipile's unified endpoint.

02

Certify in parallel: Submit your own Google app for OAuth verification while running your integration in production. Unipile supports this parallel track.

03

Switch to BYOC: Once Google approves your app, activate Bring-Your-Own-Credentials mode. Your Google OAuth refresh token lifetime becomes indefinite in production. Unipile continues managing refresh infrastructure.

Unipile Email API - List messages (Gmail, managed tokens) No token management needed
# List emails via Unipile - refresh token handled server-side import requests headers = { "X-API-KEY": "YOUR_UNIPILE_API_KEY", "accept": "application/json", } # account_id = authenticated user's linked account ID response = requests.get( "https://api7.unipile.com:13046/api/v1/emails", params={"account_id": "acc_XXXXXXXX"}, headers=headers, ) # Google OAuth refresh token is refreshed automatically by Unipile emails = response.json()["items"]

Google OAuth Refresh Token - FAQ

Common questions about Google OAuth refresh token expiration, lifetime, and the google oauth2 refresh token lifecycle.

Yes, under 6 specific conditions. The most common is the 7-day testing limit: if your app is in "Testing" status in Google Cloud Console, all refresh tokens expire after 7 days. In production with a verified app, tokens are effectively permanent unless: (1) unused for 6 months, (2) user revokes access, (3) password change with Gmail scopes, (4) 50-token cap exceeded, or (5) app loses verification for sensitive scopes. Understanding Google OAuth verification is key to avoiding unexpected expiration.

Google OAuth refresh token lifetime depends on your app's status. In testing mode: 7 days maximum, regardless of use. In production (verified app): no fixed expiration - tokens last indefinitely as long as they are used at least once every 6 months, the 50-token cap is not exceeded, and the user has not revoked access. Google Workspace internal apps also have no 7-day limit.

The google oauth refresh token 7-day expiration applies when your OAuth consent screen status is "Testing" in Google Cloud Console. Google enforces this limit on all unverified applications as a security measure. It also coincides with the 100 test user limit. The fix is to publish your app and complete Google OAuth verification (for production) or set the app to "Internal" if it's Workspace-only.

To prevent the google oauth2 refresh token from expiring due to 6-month inactivity: schedule a monthly POST to https://oauth2.googleapis.com/token with grant_type=refresh_token. This resets the inactivity clock. Note that making Gmail API calls with the existing access token does NOT count as "using" the refresh token - only the token exchange endpoint resets the timer. Store tokens server-side and never re-prompt users unnecessarily to stay under the 50-token cap.

invalid_grant means your google oauth refresh token expiration has been triggered or the token is invalid. Main causes: token expired (7-day testing limit or 6-month inactivity), user revoked access from Google Account settings, 50-token-per-client-user cap was exceeded and this token was displaced, password change with Gmail scopes, or mismatched client credentials. See the full Google OAuth errors guide for detailed remediation steps per cause.

You cannot obtain a new Google OAuth refresh token without user interaction - by design. Refresh tokens are only issued during the user-consent authorization flow. If your token is expired or revoked, you must redirect the user through the OAuth flow again. Adding prompt=consent forces a new consent screen and issues a new token, but counts against the 50-token cap. The best practice is to prevent expiration in the first place: store tokens securely, implement keep-alive refreshes, and handle invalid_grant errors gracefully by prompting re-authorization only when necessary.

POST to https://oauth2.googleapis.com/token with Content-Type: application/x-www-form-urlencoded and body params: client_id, client_secret, refresh_token, and grant_type=refresh_token. The response returns a new access_token valid for 3,600 seconds. If the response contains "error": "invalid_grant", the google api refresh token is no longer valid and user re-authorization is required. See the code samples in section 5 for curl, Python, and Node.js implementations.

Still have questions about Google OAuth refresh tokens? Our team is here to help.

Talk to an expert
en_USEN