OAuth 2.0 with Google API's
๐ OAuth 2.0 with Google APIs โ From โMagicโ to Mental Model โจ
I recently went through a full OAuth 2.0 setup for a brand-new Google account, enabling Gmail, Drive, Docs, and Sheets API access.
Everything worked flawlessly โ
but it felt a bit like magic ๐ช
This post is my attempt to:
- demystify what actually happened
- explain why OAuth feels opaque the first time
- show how developers usually avoid dealing with this more than once
๐งฑ The Setup (What I Actually Did)
โ๏ธ Google Cloud Console
- Created a new project
- Enabled APIs:
- ๐ง Gmail API
- ๐ Google Drive API
- ๐ Google Docs API
- ๐ Google Sheets API
- Created an OAuth 2.0 Client ID (Desktop App)
- Configured the OAuth consent screen:
- App name
- External audience
- Published to production
- Scopes did not require verification โ
- Downloaded the OAuth client JSON
๐ The OAuth Flow
- Used the client JSON to construct a consent URL
- Opened the URL and approved access
- Got redirected to
http://localhostwith an authorizationcode - Exchanged the code for tokens
- Stored the refresh token
- Successfully accessed Gmail, Drive, Docs, and Sheets APIs ๐
Google now shows my app under Third-party connections, and I can revoke access at any time.
๐ค Why This Feels Like Magic
OAuth looks complex because:
- ๐ Redirects feel opaque
- ๐ Tokens look scary
- ๐ Everyone says โjust use the SDKโ
- ๐งพ Docs explain what to do, not why
But underneath, OAuth 2.0 (Google flavor) is just:
- One GET request (consent)
- One redirect (authorization code)
- One POST request (token exchange)
- Saving a JSON file
Thatโs it. No sorcery involved.
๐งญ OAuth Flow โ Visual Overview
flowchart LR
A[๐ค User opens Consent URL] --> B[๐ Google Consent Screen]
B -->|Allow| C[๐ Redirect to localhost with code]
C --> D[๐ฆ App exchanges code for tokens]
D --> E[๐ Refresh token stored]
E --> F[๐ก API calls with access token]
๐ ๏ธ Building the Consent URL (No SDK, No Magic)
From the downloaded client_secret.json, you already have:
client_idauth_uriredirect_uris
The consent URL is just:
1
2
3
4
5
6
7
https://accounts.google.com/o/oauth2/auth
?client_id=CLIENT_ID
&redirect_uri=http://localhost
&response_type=code
&access_type=offline
&prompt=consent
&scope=SCOPE_1 SCOPE_2 ...
๐ Notes:
- Scopes are space-separated
- URL-encode spaces as
%20 access_type=offlineโ refresh tokenprompt=consentโ force issuance
๐ Example Scopes
https://www.googleapis.com/auth/gmail.readonlyhttps://www.googleapis.com/auth/drivehttps://www.googleapis.com/auth/documentshttps://www.googleapis.com/auth/spreadsheets
Open the URL โ click Allow โ redirect happens.
๐ Exchanging the Code for Tokens
After consent, the browser redirects to something like:
1
http://localhost/?code=4/0AbCdEfGhIj...
That code is exchanged for tokens via a simple HTTP POST:
1
2
3
4
5
6
curl -X POST https://oauth2.googleapis.com/token \
-d client_id=CLIENT_ID \
-d client_secret=CLIENT_SECRET \
-d code=AUTH_CODE \
-d grant_type=authorization_code \
-d redirect_uri=http://localhost
Google responds with JSON:
1
2
3
4
5
6
7
{
"access_token": "...",
"expires_in": 3599,
"refresh_token": "...",
"scope": "...",
"token_type": "Bearer"
}
โจ This is the entire โmagicโ.
๐ The Refresh Token Is the Real Prize
- โฑ๏ธ Access tokens expire (~1 hour)
- โป๏ธ Refresh tokens live until:
- user revokes access
- app is deleted
- consent is replaced
Refreshing later is just another POST:
1
2
3
4
5
curl -X POST https://oauth2.googleapis.com/token \
-d client_id=CLIENT_ID \
-d client_secret=CLIENT_SECRET \
-d refresh_token=REFRESH_TOKEN \
-d grant_type=refresh_token
No browser. No UI. No drama.
๐คฏ Do Developers Really Do This Every Time?
No. Absolutely not.
Hereโs how reality looks.
1๏ธโฃ OAuth Is Done Once per Project
- painful once
- copy-pasted forever
- never touched again unless scopes change
OAuth is treated like database migrations.
2๏ธโฃ SDKs Exist to Hide This
Libraries:
- build URLs
- start localhost listeners
- parse redirects
- store tokens
They donโt change OAuth โ they just hide it.
3๏ธโฃ OAuth Is Centralized in Teams
In real systems:
- one service handles OAuth
- everyone else consumes tokens
- most developers never see consent screens
OAuth becomes infrastructure, not app logic.
4๏ธโฃ Production Often Uses Service Accounts
For server-to-server access:
- no browser
- no user
- no consent
- no refresh tokens
Just signed JWTs and IAM roles ๐
๐ง Why Itโs Still Worth Understanding
Even if you never do this manually again:
- ๐ ๏ธ Debugging OAuth failures gets easy
- ๐ Scope issues stop being mysterious
- ๐ซ Revocation suddenly makes sense
- ๐งโโ๏ธ Security reviews stop being scary
Most importantly:
OAuth is not authentication.
OAuth is delegated API access encoded as JSON.
Once that clicks, the magic disappears.
โจ Final Thoughts
OAuth feels complicated because it tries to solve:
- trust
- consent
- revocation
- least privilege
- cross-app access
But the protocol itself is simple.
Do it once by hand and youโve seen behind the curtain ๐ญ
Next time, youโll happily let a tool do it for you ๐