Common Google OAuth & Gmail API Errors (and How to Fix Each One)

Google OAuth Guide

Common Google OAuth & Gmail API Errors (and How to Fix Each One)

Every developer integrating Gmail or Google Calendar with Google OAuth will hit at least one of these google oauth errors. This guide consolidates all 7 common Google OAuth errors in one place - with the exact cause and the step-by-step fix for each one. Understanding these google oauth errors will save hours of debugging.

oauth_callback.py
# Google OAuth token exchange import requests token_response = requests.post( "https://oauth2.googleapis.com/token", data={ "code": authorization_code, "client_id": CLIENT_ID, "client_secret": CLIENT_SECRET, "redirect_uri": REDIRECT_URI, "grant_type": "authorization_code" } )
error: redirect_uri_mismatch
redirect_uri_mismatch invalid_grant admin_policy_enforced access_denied invalid_scope
Quick Reference

Quick reference: every Google OAuth error at a glance

A single-table summary of all 7 google oauth errors covered in this guide - stage where it occurs, root cause, and the quick fix link to the detailed section below. Bookmark this table as a reference when debugging google oauth errors in development or production.

Error message Stage Root cause Quick fix
redirect_uri_mismatch Authorization The redirect URI in your request does not exactly match one registered in Google Cloud Console Fix it
admin_policy_enforced Authorization A Workspace super admin has restricted which OAuth apps or scopes users in the org can grant access to Fix it
access_denied Authorization App is in Testing mode and the user is not a test user, or app requests restricted scopes without verification Fix it
invalid_grant Token refresh Refresh token expired, revoked, or used more than once (single-use auth code) Fix it
Consent screen missing Google Cloud Console New Google Cloud UI moved OAuth consent screen; also requires Owner/Editor role on the project Fix it
invalid_scope Authorization Scope URL typo or the corresponding Google API is not enabled in the project Fix it
Google hasn't verified Authorization App uses sensitive/restricted scopes but has not completed Google verification; Testing mode caps at 100 users Fix it
redirect_uri_mismatch Authorization
Root causeRedirect URI in request does not exactly match a registered URI in Google Cloud Console
admin_policy_enforced Authorization
Root causeWorkspace super admin blocked the app or scope for the organization
access_denied Authorization
Root causeApp in Testing mode, user not added as test user, or restricted scopes without verification
invalid_grant Token refresh
Root causeRefresh token expired (6 months inactivity), revoked, or single-use auth code was reused
Consent screen missing Google Cloud Console
Root causeNew Google Cloud UI moved OAuth consent screen to "OAuth Overview"
invalid_scope Authorization
Root causeScope URL typo or API not enabled in the project
Google hasn't verified Authorization
Root causeSensitive/restricted scopes without verification; Testing mode 100-user cap
Error 400

Error 400: redirect_uri_mismatch

This is the most common Google OAuth error for developers setting up a new integration. It fires during the authorization step - before any token is issued.

The exact error message

Error 400: redirect_uri_mismatch The redirect URI in the request did not match a registered redirect URI. error=redirect_uri_mismatch

Cause

Root cause

Google compares the redirect_uri parameter you pass in your authorization URL with the list of Authorized redirect URIs registered in your OAuth client in Google Cloud Console. Even a single character difference - a trailing slash, http vs https, or a different port - triggers this error.

Fix (step by step)

Steps to fix
1 Open Google Cloud Console - APIs & Services - Credentials.
2 Click on your OAuth 2.0 Client ID to edit it.
3 Under Authorized redirect URIs, add the exact URI you are passing in your code - e.g. https://yourapp.com/oauth/callback. The value must be character-for-character identical, including scheme, port, and trailing slash.
4 Click Save. Changes can take a few minutes to propagate.
5 In your code, make sure the redirect_uri value you pass to the authorization endpoint and to the token exchange endpoint are identical.

redirect_uri_mismatch on localhost

During local development, register the exact localhost URI you use - for example http://localhost:3000/callback. Google allows http:// (not just https://) for localhost URIs. If you change your dev port, remember to update the registered URI.

Gotcha: Authorized JavaScript origins vs redirect URIs

These are two separate fields and they serve different purposes. Authorized JavaScript origins are used for browser-side OAuth flows (implicit flow, Google Identity Services). Authorized redirect URIs are used for server-side authorization code flows. Adding a URI to JavaScript origins will NOT fix a redirect_uri_mismatch error - you must add it to the redirect URIs field. A Google OAuth client can have up to 100 redirect URIs registered.

Error 400 / Admin

Error 400: admin_policy_enforced

This error is not a bug in your code. It is an organizational policy enforced by a Google Workspace super administrator. A regular developer cannot fix it alone.

The exact error message

Error 400: admin_policy_enforced Google Account is unable to be used for authorization because of your organization's policies. Contact your admin for more info. error=admin_policy_enforced

Cause

Root cause

A Google Workspace super admin has restricted which third-party applications or OAuth scopes users in the organization can grant access to. This is configured via API Controls in the Google Admin Console. When an app is not on the approved list, every user in that Workspace will receive this error when they attempt to authorize it - regardless of the app's verification status.

This is a compliance and security control, not a developer-side misconfiguration. The correct resolution is always admin-side.

Fix (admin-side only)

Steps for the super admin
1 Sign in to the Google Admin Console at admin.google.com with a super administrator account.
2 Navigate to Security - Access and data control - API controls.
3 Click Manage Third-Party App Access.
4 Search for the app by its OAuth Client ID or application name. Click on it.
5 Change the app's access status from Blocked or Limited to Trusted. This allows the app to request the scopes it has declared.
6 Click Change to confirm. Users in the org can now authorize the app.
Note: regular users cannot fix this

A user who encounters admin_policy_enforced cannot resolve it themselves. They need to contact their Google Workspace super admin and request that the specific OAuth app be marked as Trusted. If the user is the admin, they can follow the steps above. If the domain enforces a strict "Allow specific apps" policy, the app must first be explicitly added to the approved list before it can be set to Trusted.

If you are building internal tooling and want to avoid per-user OAuth consent entirely, a service account with Domain-Wide Delegation is the alternative - see our Gmail service account & DWD guide.

access_denied

access_denied & "This app is blocked" (unverified app)

Users see a "This app is blocked" screen or receive access_denied in the OAuth callback. This one has multiple root causes depending on whether your app is still in Testing mode or targeting restricted scopes.

The exact error message

Access blocked: [Your App Name] has not completed the Google verification process error=access_denied -- or -- This app is blocked. This app tried to access sensitive info in your Google Account. Contact the developer for more info.

Causes

App in Testing mode + user not a test user

While your OAuth app is in "Testing" publishing status, only users explicitly added as test users can authorize it. Anyone else gets access_denied immediately.

Testing mode 100-user cap reached

Testing mode is limited to 100 unique test users at any time. Once you hit 100, new users cannot authorize the app even if added.

Sensitive or restricted scopes without verification

Scopes like gmail.modify or gmail.send are Sensitive scopes. Apps requesting them must complete Google's app verification process before real users can grant access.

Restricted scopes (most severe)

A small number of scopes (e.g. full Gmail access) are Restricted and require a third-party security audit (CASA) in addition to verification.

Fix

For Testing mode - add test users
1 In Google Cloud Console, go to APIs & Services - OAuth consent screen.
2 Under Test users, click Add users and add the Gmail address of each user who needs access during testing.
3 Save. That user can now authorize the app while it remains in Testing mode.
For Production - submit for verification + CASA if needed
1 Ensure your OAuth consent screen is fully filled out: app name, support email, homepage URL, privacy policy URL.
2 On the OAuth consent screen page, click Publish App to move to Production, which triggers the verification review submission for sensitive scopes.
3 For Restricted scopes, complete a CASA Tier 2 security assessment. See the full Google OAuth setup guide for the verification and CASA workflow.
invalid_grant

invalid_grant: "reconnect your Gmail account"

The gmail api invalid grant error is one of the most confusing in production - it breaks silently for a subset of users and requires a new OAuth flow to recover. Understanding the refresh token lifecycle is the key to handling it properly.

The exact error message

{"error": "invalid_grant", "error_description": "Token has been expired or revoked."} -- or -- {"error": "invalid_grant", "error_description": "Bad Request"}

Cause: the refresh token lifecycle

6 months of inactivity - Google revokes refresh tokens that have not been used for 6 months. A user who linked their account and then stopped using your app will get this error on the next attempt.
User changed their Google password - changing the Google account password revokes all existing OAuth tokens for that account, including refresh tokens issued to third-party apps.
Scope change on re-authorization - if you re-authorize with a different set of scopes than the original grant, Google revokes the previous refresh token.
Testing mode = 7-day token expiry - while your app is in Testing publishing status, refresh tokens expire after 7 days regardless of usage. This is the most common reason developers see invalid_grant after a week of testing.
Authorization code used more than once - the authorization code returned by Google in the OAuth redirect is single-use. If you call the token endpoint more than once with the same code, all subsequent calls return invalid_grant.

Fix: re-authorize with access_type=offline + prompt=consent

build_auth_url.py
from google_auth_oauthlib.flow import Flow flow = Flow.from_client_secrets_file( 'client_secrets.json', scopes=['https://www.googleapis.com/auth/gmail.readonly'], redirect_uri=REDIRECT_URI ) # access_type=offline → get a refresh token # prompt=consent → force re-consent, always returns a new refresh token auth_url, state = flow.authorization_url( access_type='offline', prompt='consent' ) # Store the NEW refresh_token from the response # old token is now invalid -- update your DB
New refresh token issued - store it and discard the old one

To avoid invalid_grant in production: always use access_type=offline and prompt=consent when initiating the OAuth flow, update your stored refresh token every time the user re-authorizes, detect invalid_grant errors and trigger a graceful re-authorization UI (a "reconnect your Gmail account" prompt), and move your app out of Testing mode to get permanent tokens.

Skip refresh-token management Build on Unipile's managed OAuth - no token lifecycle to handle
Build it with Unipile
Google Cloud Console

The OAuth consent screen won't show in Google Cloud Console

This is the highest-volume search query in this cluster (390+ monthly searches). The "OAuth consent screen" page appears to have disappeared from Google Cloud Console for many developers in 2024-2026 due to a UI redesign. It has not been removed - it moved.

Symptom

What you see

You open Google Cloud Console and navigate to APIs & Services, but the "OAuth consent screen" menu item is either missing or clicking it redirects you to a new "OAuth Overview" page that shows a summary dashboard instead of the configuration form you expected.

Causes

1 Google redesigned the Google Cloud Console in 2024 and moved the OAuth consent screen configuration into a new "OAuth Overview" section under APIs & Services. The direct edit form is now one level deeper.
2 You may have Viewer role instead of Editor or Owner role on the Google Cloud project. Viewer-role accounts can see the overview but cannot access the consent screen configuration form.
3 You may be on the wrong project. Each project has its own OAuth consent screen. If you have multiple projects, check the project selector at the top of the console.
4 You have not yet selected a User type (Internal or External) for the OAuth consent screen. This selection is required before the configuration form becomes accessible.

Fix (step by step)

Steps to access the OAuth consent screen configuration
1 Verify you are on the correct Google Cloud project using the project dropdown at the top of the page. If not, switch to the project where your OAuth client ID is configured.
2 Confirm your role: go to IAM & Admin - IAM and verify you have Editor or Owner role. Viewer role cannot edit the consent screen.
3 Navigate to APIs & Services - OAuth overview. You will see a summary page.
4 Look for the "Edit App" button or the "Branding" / "Audience" / "Scopes" tabs. These are the sections of what was formerly a single "OAuth consent screen" configuration page.
5 If you have never set up an OAuth consent screen on this project, click Get started and choose your User type: Internal (Workspace users only, no verification needed) or External (any Google account, verification required for sensitive scopes).
6 Fill in all required fields: app name, support email, and for External apps: homepage URL and privacy policy URL.
Quick tip: you can also navigate directly via this URL pattern (replace YOUR_PROJECT_ID): https://console.cloud.google.com/apis/credentials/consent?project=YOUR_PROJECT_ID. This deep link bypasses the overview page and goes straight to the consent screen configuration. For a full walkthrough of every configuration field, user type selection, and the 100-user testing cap, see our OAuth consent screen setup guide.

Weeks of verification.
Use Unipile's key and start now.

Don't lose customers waiting on Google's review. Connect Gmail accounts in 5 minutes with our pre-verified developer credentials.

SOC 2 - GDPR - No app review needed - Switch to your own key anytime
CASA Tier 2 Certified
connect-gmail.shcurl
# No Google Cloud Console. No review.# Connect any Gmail account in 5 min. curl -X POST "https://api.unipile.com/v1/accounts" \ -H "X-API-KEY: $UNIPILE_KEY" \ -d '{ "provider": "GOOGLE_OAUTH", "use_unipile_credentials": true }'
invalid_scope

invalid_scope

A typo in the scope URL or a disabled API will cause Google to reject the entire authorization request before any user interaction happens.

The exact error message

{"error": "invalid_scope", "error_description": "Some requested scopes were invalid. {valid=[https://mail.google.com/], invalid=[gmail.readonly]}"} -- or on the consent screen URL -- error=invalid_scope&error_description=Some+requested+scopes+were+invalid

Cause

Two common root causes: (1) the scope value is a short name like gmail.readonly instead of the full URL https://www.googleapis.com/auth/gmail.readonly, or (2) the Gmail API (or any other Google API you are scoping to) is not enabled in the Google Cloud project.

Common Gmail scopes and their correct URLs

Scope URL (use the full URL) What it allows Type
https://www.googleapis.com/auth/gmail.readonly Read all messages and threads Sensitive
https://www.googleapis.com/auth/gmail.send Send email on behalf of the user Sensitive
https://www.googleapis.com/auth/gmail.modify Read, compose, send, delete threads Sensitive
https://mail.google.com/ Full mailbox access (IMAP/SMTP) Restricted
https://www.googleapis.com/auth/userinfo.email Read user's email address only Basic
https://www.googleapis.com/auth/gmail.readonly Read all messages and threads Sensitive
https://www.googleapis.com/auth/gmail.send Send email on behalf of the user Sensitive
https://www.googleapis.com/auth/gmail.modify Read, compose, send, delete threads Sensitive
https://mail.google.com/ Full mailbox access (IMAP/SMTP) Restricted

Fix

Steps to fix invalid_scope
1 Check that you are using the full scope URL (starts with https://www.googleapis.com/auth/ or https://mail.google.com/). Never use the short form like gmail.readonly.
2 In Google Cloud Console, go to APIs & Services - Enabled APIs & services. Search for Gmail API and confirm it shows as "Enabled". If not, click Enable.
3 Confirm the scope is listed in your OAuth consent screen under Scopes for Google APIs. If it is missing, add it.
4 Re-test your authorization URL. For a full list of valid Gmail scopes and their sensitivity classification, see the Gmail API scopes guide.
Verification

"Google hasn't verified this app" & the 100-user cap

The warning screen "Google hasn't verified this app" appears when an unverified app requests sensitive or restricted scopes. While users can proceed by clicking "Advanced" and then "Go to [app name] (unsafe)", this is not suitable for production - and Testing mode caps your app at 100 unique users total.

Cause

Root cause

When your app requests Sensitive scopes (like gmail.readonly or gmail.send), Google displays this warning screen to every user until you complete the verification review. For Restricted scopes, you also need to pass a third-party security audit (CASA Tier 2).

While in Testing publishing status, this warning screen is also displayed even for test users, and the total number of test users allowed is capped at 100. Tokens for test users expire after 7 days.

Fix

Path to production for sensitive/restricted scopes
1 Complete the OAuth consent screen: app name, support email, homepage URL, and privacy policy URL must all be provided.
2 On the OAuth consent screen / Audience page, click Publish App (moves status from Testing to Production, triggering Google's verification flow).
3 For Sensitive scopes: complete Google's verification review. This involves confirming your identity, explaining your use of each sensitive scope, and linking a YouTube video demonstrating the OAuth flow.
4 For Restricted scopes (e.g. https://mail.google.com/): additionally complete a CASA Tier 2 security assessment by a Google-approved assessor.
5 For the full step-by-step consent screen setup, scope selection, and verification workflow, see the Google app verification and CASA guide.
Independent technical intermediary

These errors disappear when the OAuth project is already certified

The "Google hasn't verified this app" screen, the 100-user cap, and the 7-day token expiry in Testing mode are all symptoms of owning and managing your own Google Cloud project. An independent technical intermediary that acts on behalf of each authenticated user - and has already completed CASA Tier 2 certification - removes this entire overhead from your side. Your users authorize once; token lifecycle, scope compliance, and re-verification are handled at the platform level.

This is not a workaround for Google's security review. Unipile has independently completed CASA Tier 2 and is not affiliated with, endorsed by, or sponsored by Google.

Ship on already-certified Google OAuth
Strategy

How to avoid this entire class of Google OAuth errors

Looking across all 7 google oauth errors in this guide, a pattern emerges. Every single one originates from the same root: managing your own Google Cloud project and its OAuth configuration manually. These google oauth errors are not random - they are structural consequences of owning an unverified OAuth project, from redirect URI mismatches and token rotation failures to the 100-user cap and consent screen rejections.

There is another way. Using an independent technical intermediary that acts on behalf of each authenticated user - one that has already completed Google's verification review and CASA Tier 2 security certification - shifts every one of these failure modes off your plate. The comparison below shows exactly which errors disappear and which infrastructure Unipile handles instead. See the Unipile Google OAuth documentation for the full integration guide.

Fixing it yourself vs. Unipile

Every error in this guide: who owns the fix?

The 7 Google OAuth errors covered above share a common root: you own the Google Cloud project, so you own every failure mode. Here is a side-by-side look at what that means in practice.

Fixing it yourself Your responsibility
redirect_uri_mismatch Manage every redirect URI in Google Cloud Console
admin_policy_enforced Depends on each user's Workspace admin - out of your control
access_denied / app blocked Google verification process + test user management
invalid_grant Build and maintain your own refresh-token rotation logic
Consent screen issues Configure and maintain the OAuth consent screen yourself
invalid_scope Track which restricted scopes require Google verification
Unverified app + 100-user cap Run Google verification and CASA Tier 2 assessment yourself
You own and debug all of it
With Unipile Handled
Hosted auth link - no consent screen to configure No redirect URI management, ever
Redirect URIs handled for you redirect_uri_mismatch simply cannot occur
Refresh tokens managed automatically No "reconnect your Gmail" errors reaching your users
Connect on Unipile's already-certified Google OAuth key No unverified-app warning, no 100-user cap
CASA Tier 2 Certified Unipile's Google OAuth key - independent technical intermediary
Skip building and certifying your own Google Cloud project - connect your users' Gmail on Unipile's already-certified key, then switch to your own when you're ready (BYOC)
Access restricted Gmail scopes without waiting for your own Google verification to complete
Unipile acts as an independent technical intermediary, processing requests on behalf of each authenticated user
Ship now on Unipile's certified key - own it later Start connecting your users' Gmail accounts today via Unipile's CASA Tier 2 certified Google OAuth key. Run your own Google Cloud verification in parallel. When it clears, switch to your own credentials with Bring Your Own Credentials (BYOC) - your users see your brand, Unipile continues handling the infrastructure.
These error classes simply don't occur

The key distinction: Unipile has already completed Google's security review and CASA Tier 2 assessment for the connections it brokers on your behalf. This is not a workaround for Google's security review - Unipile has already passed it. Your users get a clean consent screen (no "unverified app" warning), your app ships immediately, and you can pursue your own Google Cloud verification in parallel without any production deadline pressure.

Build your Gmail integration without touching Google Cloud Console Link Gmail accounts on Unipile's already-certified Google OAuth key. No redirect URI configuration, no token rotation logic, no unverified-app warnings for your users.
Ship on Unipile's certified key

Compliance note: Unipile is an independent technical intermediary, not affiliated with, endorsed by, or sponsored by Google. Unipile's Google OAuth client is CASA Tier 2 certified, enabling your users to authorize Gmail access without an "unverified app" warning for connections brokered through Unipile. This is not a workaround for Google's security review - Unipile has already passed it for the connections it brokers on behalf of each authenticated user. Users can revoke access at any time via their Google Account permissions page.

Unipile - Google OAuth Errors FAQ

Google OAuth errors FAQ

Answers to the most common questions about Google OAuth errors and Gmail API errors, covering token lifecycle, admin policies, redirect URIs, and Google Cloud Console configuration.

01 What does admin_policy_enforced mean?

admin_policy_enforced means a Google Workspace super administrator has blocked your app or the specific OAuth scopes it requests from being authorized by users in that organization. It is an organizational access control policy, not a bug in your code. The fix requires action from the Workspace super admin in the Google Admin Console under Security > API controls > Manage Third-Party App Access.

No. A regular user cannot fix admin_policy_enforced. Only a Google Workspace super administrator can resolve this error by marking the app as Trusted in the Admin Console. The affected user needs to contact their IT administrator or Workspace super admin and request that the specific OAuth app be added to the approved list.

The redirect_uri_mismatch on localhost happens when the URI you register in Google Cloud Console does not exactly match the URI your local development server uses. For example, registering http://localhost:3000/callback but running on port 3001, or forgetting a trailing slash. Google allows http:// (not just https://) for localhost URIs. Register the exact URI your local server uses, including the correct port number.

No. Authorized JavaScript origins and Authorized redirect URIs are two separate fields. JavaScript origins are used for browser-side OAuth flows only. To fix redirect_uri_mismatch, you must add the URI to the Authorized redirect URIs field, not to JavaScript origins.

A single Google OAuth 2.0 client can have up to 100 Authorized redirect URIs registered. This allows you to register URIs for different environments (local development, staging, production) and different callback paths within the same client.

If your app is in Testing publishing status, Google refresh tokens expire after 7 days regardless of usage. This is by design for unverified apps. Move to Production status by clicking Publish App on the OAuth consent screen page to get long-lived tokens. In Production, refresh tokens remain valid as long as the user uses your app at least once every 6 months. For a managed alternative, visit our managed Gmail API solution.

Google revokes refresh tokens that have not been used for 6 months (approximately 180 days). Tokens are also revoked when: the user changes their Google account password, the user revokes app access in their Google Account security settings, you re-authorize with different scopes, or the total refresh tokens for a single user-app pair exceeds 50 (oldest get revoked first). For the full picture on building robust email integrations, see our complete Email API guide.

Google redesigned the Cloud Console in 2024. The OAuth consent screen configuration is now inside APIs & Services > OAuth overview. Click Edit App or use the Branding, Audience, and Scopes tabs. Also check: you need Editor or Owner role on the project (Viewer cannot access the form), and make sure you are on the correct project using the project selector at the top of the console.

Still hitting a Google OAuth error not listed here? Skip the debugging and let Unipile handle Gmail OAuth for you.

Build Now
en_USEN