How Google's OAuth Consent Screen Actually Works
A practitioner's walkthrough of Google's OAuth verification tiers, scope categories, and the pitfalls (100-user caps, CASA audits, brand verification) that trip up anyone wiring an app into Gmail, Calendar, or Drive.
CONTEXT
Any project that touches Gmail, Calendar, or Drive on a user's behalf — including agent tooling that needs to read a mailbox or write a calendar event — runs into Google's OAuth consent and verification system almost immediately. It's not optional paperwork; it changes what your app can do and how many users it can have before you've finished it.
The mechanics of OAuth 2.0 itself — authorization code, redirect URI, token exchange — are the easy part and well documented everywhere. The part that actually gates a project is Google's layer on top: what the consent screen shows, which scopes require review, and what happens to your app before that review completes. Get this wrong and you find out not at launch but weeks in, when your app silently stops letting in new users.
The three scope tiers
Google buckets every OAuth scope into one of three categories, and the category — not the API you're calling — determines what you have to do before going to production.
- Non-sensitive scopes — basic profile info, things like
openidoremail. No verification required. - Sensitive scopes — access to private data with moderate blast radius: reading Calendar events, managing Contacts, deleting a YouTube video. Requires standard app verification.
- Restricted scopes — broad access to the most sensitive user data: full Gmail access (
gmail.readonly,gmail.modify), Drive file access, Google Fit, and similar. Requires verification plus an annual third-party security assessment.
Most of the scopes an agent-style tool wants — read a mailbox, create Calendar events, list Drive files — land in the sensitive or restricted tier by default. calendar.events is sensitive; broad Gmail or Drive scopes are restricted. If you can get away with a narrower, purpose-built scope (Google has been adding these, e.g. Gmail's gmail.addons.current.message.readonly instead of full mailbox read) it's worth the trade of reduced functionality for a much lighter review.
Testing vs. production: the 100-user cap
Every OAuth client starts in Testing publishing status. In this state you add specific Google accounts as test users (typically capped around 100), those users see an "unverified app" warning before consent, and their authorization expires after 7 days, so they have to re-consent weekly. This is fine for development and fine for a genuinely internal tool with a fixed, small user list.
The moment you flip a client to In production without completing verification, a different and much sharper limit applies: Google caps the app at 100 total users, for the lifetime of that OAuth client — not 100 concurrent, not 100 per month, 100 ever. Creating a new OAuth client ID or redeploying the app does not reset it; the cap is tied to the Cloud project's client. There is no way to raise it short of completing verification.
This is the mistake that catches people off guard: an app looks done, ships to production, picks up a trickle of real users, and then new sign-ups start failing at exactly user 101 with no obvious error explaining why. If you know from the start that an app will have more than a handful of real users, budget for verification before launch rather than treating it as a later cleanup task.
What verification actually checks
Standard verification (for sensitive scopes) is a manual review, typically 2–3 business days once submitted, that checks:
- OAuth consent screen accuracy — app name, logo, support email, and a privacy policy URL that's actually reachable and actually describes what the app does with the requested data.
- Scope justification — for each sensitive scope requested, a written explanation of why the app needs it and, usually, a short screen-recorded demo showing the scope in use inside the app's real UI. Google checks this against the narrowest-scope-necessary principle; asking for
gmail.modifywhen you only ever read messages is a common rejection reason. - Domain ownership — any domain referenced in the consent screen (homepage, privacy policy, terms) has to be verified in Google Search Console, which itself takes up to 24 hours to confirm ownership and up to 72 hours for DNS propagation depending on registrar. Do this first; it's the long pole and easy to start early.
- Brand verification — separate from scope review, this confirms the app name and logo aren't impersonating another product or organization.
Restricted scopes: CASA on top
If any requested scope is restricted (full Gmail, Drive, Fit, etc.), standard verification isn't the end of it. Google also requires a security assessment under CASA (Cloud Application Security Assessment), an audit framework built on OWASP's Application Security Verification Standard (ASVS) and performed by a Google-approved third-party assessor.
CASA is tiered by risk (assurance levels AL1/AL2), with the required level depending on user count, scopes requested, and how the app handles the data downstream (e.g., whether restricted data ever leaves Google's infrastructure to sit on your own servers). It is not free, it is not instant, and — this is the part people miss — it isn't one-and-done: apps have to be reassessed annually, and Google can bump the required tier if your user base or data handling changes. For a side project or an internal agent tool, this is often the deciding factor in whether to request the restricted scope at all versus finding a narrower alternative.
Exceptions worth knowing
Verification isn't required in a handful of specific cases: personal-use apps only you will ever authorize, apps confined to development/testing/staging, apps that only touch data the app itself owns (not other users' data), and apps used exclusively inside a single Google Workspace organization via domain-wide delegation. If your "app" is really a personal automation script hitting your own Gmail, you can often stay in Testing mode indefinitely and never trigger any of this — the moment it needs to work for someone else's account is the moment the rules above apply.
Practical sequence for a new integration
- Scope the request down first. Look for the narrowest scope that does the job before assuming you need the broad one — the difference between sensitive and restricted tiers is the difference between a few days of review and an ongoing paid audit.
- Verify the domain early. DNS propagation and Search Console confirmation can eat three days on their own; kick this off before you're ready to submit anything else.
- Write the scope justification and record the demo as you build, not after — it's much easier to narrate the actual feature than to reconstruct why you needed a scope six weeks later.
- Decide deliberately whether you need a restricted scope at all. If the answer is yes, treat the CASA assessment as a recurring line item, not a one-time gate, and budget for the annual re-audit.
- If the app truly has a fixed, small, known set of users, staying in Testing with those accounts explicitly added is a legitimate long-term posture — it avoids verification entirely, at the cost of the 7-day re-consent cadence and the up-front 100-test-user ceiling.
None of this is exotic once you've been through it once, but the failure mode — an app that works perfectly in every test, then hard-stops at 100 real users, or gets rejected for asking for more access than it demonstrably uses — is entirely avoidable by treating verification as part of the build, not an afterthought bolted on at launch.