OAuth 2.0 Explained: How "Sign in with Google" Really Works
A step-by-step guide to how "Sign in with Google" really works — OAuth 2.0, OpenID Connect, and the Authorization Code Flow with PKCE, without the deep detail.

Every time you click "Sign in with Google," a precisely choreographed exchange unfolds across your browser, the app you're using, and Google's servers — all in a few hundred milliseconds, and crucially, without the app ever seeing your Google password. That choreography is OAuth 2.0, extended by OpenID Connect. This guide traces the exact requests and responses, step by step, so you can see how social login really works.
⛔ The core insight — Sharing a password shares your identity. What you actually want to share is a narrow, revocable, time-boxed permission. OAuth exists to make that distinction real.
The vocabulary, in one table
OAuth conversations collapse the moment two people use the same word for different things. Here is the glossary up front.
| Term | One-line definition | Answers the question |
|---|---|---|
| Authentication (AuthN) | Proving who a user is. | "Are you really Ashutosh?" |
| Authorization (AuthZ) | Deciding what an identity may do. | "Are you allowed to read these files?" |
| OAuth 2.0 | A framework for delegated authorization — granting an app scoped access without sharing a password. | "May this app act on my behalf?" |
| OpenID Connect (OIDC) | A thin identity layer on top of OAuth 2.0 that adds verified login. | "Who just logged in?" |
| Access Token | A short-lived key that lets a client call an API. | "What unlocks this resource?" |
| ID Token | A signed JWT asserting a user's identity (OIDC only). | "What proves who the user is?" |
| Refresh Token | A long-lived credential used to mint new access tokens. | "How do we stay logged in?" |
| JWT | JSON Web Token — a compact, signed, self-describing token format. | "What shape is the token?" |
What Is OAuth 2.0?
OAuth 2.0 is an authorization framework, not an authentication protocol. OAuth's job is to let a user (the resource owner) grant a third-party application limited, scoped access to resources hosted somewhere else, without revealing their credentials to that application.
The four roles
Every OAuth interaction is a conversation between four parties. Map them once and the rest of the protocol clicks into place.
| Role | What it is | In the "Sign in with Google" example |
|---|---|---|
| Resource Owner | The human who owns the data and grants access. | You, the Google account holder. |
| Client Application | The app requesting access on the user's behalf. | The third-party app showing the button (e.g. a notes app). |
| Authorization Server | Authenticates the user, gets consent, and issues tokens. | Google's OAuth/OIDC service at accounts.google.com. |
| Resource Server | The API that holds protected resources and accepts access tokens. | A Google API (e.g. People, Drive) — or, for pure login, the app's own backend. |
A useful distinction: the authorization server hands out tokens; the resource server consumes them.
The Three Tokens
Tokens are how OAuth replaces a password with something better. There are three that matter, and each has exactly one intended audience and one intended job.
- Access token — a short-lived credential (often 5–60 minutes) the client presents to a resource server to call an API. Its audience is the API, not the client; the client should treat it as an opaque string and never parse its contents.
- Refresh token — a longer-lived credential used to obtain new access tokens after the current one expires, without dragging the user back through a login screen. It never goes to a resource server, only to the authorization server's token endpoint, and must be stored securely.
- ID token — the piece OAuth 2.0 by itself does not provide; it is introduced by OpenID Connect. It is always a signed JWT, its audience is the client, and it exists to answer one question: who is the user that just authenticated?
⚠️ The #1 token confusion — An access token authorizes API calls; an ID token identifies the user. Never use an access token to decide who someone is, and never send an ID token to a resource server as if it were an API key. Different audiences, different jobs.
How "Sign in with Google" Really Works
Modern web and mobile apps use the Authorization Code Flow with PKCE (pronounced "pixy," Proof Key for Code Exchange, RFC 7636). It is the flow Google, Auth0, Okta, and every serious identity provider recommend today. We'll look at the whole sequence, step by step.
There are two channels. The front channel runs through the browser via redirects and is visible to the user and any browser-resident code. The back channel is a direct, server-to-server HTTPS call that exchanges the code for tokens. Tokens never travel the front channel — only a temporary authorization code does, and it is useless without the PKCE secret. That split is the heart of the flow's security.
Step 1 — The Authorization Request
When the user clicks the button, the client first generates a random code verifier and derives a code challenge from it (code_challenge = BASE64URL(SHA256(code_verifier))). It also generates a random state and a random nonce. Then it redirects the browser to Google's authorization endpoint:
Front channel — browser redirect to Google
GET https://accounts.google.com/o/oauth2/v2/auth
?response_type=code
&client_id=1234567890-abc.apps.googleusercontent.com
&redirect_uri=https://app.example.com/auth/callback
&scope=openid%20email%20profile
&state=xCSRF7Yq2k
&nonce=n-9fK3pQ1z
&code_challenge=E9Melhoa2OwvFrEMTJguCHaoeK1t8URWbuGJSstw-cM
&code_challenge_method=S256
Each parameter earns its place: response_type=code selects the Authorization Code Flow; scope=openid … requests an OIDC login plus the user's email and profile; state protects against CSRF; nonce binds the eventual ID token to this exact request; and the two code_challenge* parameters arm PKCE.
Step 2 — User Authentication & Consent
Google now takes over: it authenticates the user however it deems sufficient — session cookie, password, passkey, MFA, none of which the client ever sees — then shows a consent screen listing the requested scopes. This is the moment the password anti-pattern is designed out of existence: credentials are entered only on Google's own domain.
Step 3 — The Authorization Code
On approval, Google redirects the browser back to the client's pre-registered redirect_uri with a short-lived, single-use authorization code and the original state:
Front channel — Google redirects back to the app
HTTP/1.1 302 Found
Location: https://app.example.com/auth/callback
?code=4/0AeanS0b8xQk9…short-lived…
&state=xCSRF7Yq2k
The client's first action is to confirm the returned state equals the value it generated in Step 1. A mismatch means the response may have been forged, and the request is dropped. The code itself is intentionally near-worthless on its own: it expires in seconds and, thanks to PKCE, cannot be redeemed without the matching code verifier.
Step 4 — The Token Exchange
Now the client switches to the back channel. Its server makes a direct POST to Google's token endpoint, presenting the code and — the PKCE payoff — the original code_verifier:
Back channel — server-to-server token request
POST /token HTTP/1.1
Host: oauth2.googleapis.com
Content-Type: application/x-www-form-urlencoded
grant_type=authorization_code
&code=4/0AeanS0b8xQk9…
&redirect_uri=https://app.example.com/auth/callback
&client_id=1234567890-abc.apps.googleusercontent.com
&code_verifier=dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk
&client_secret=GOCSPX-… ← confidential (server-side) clients only
Google recomputes SHA256(code_verifier) and checks it against the code_challenge it stored in Step 1. If they match, the same client that started the flow is the one finishing it, and Google responds with the tokens:
Token response
{
"access_token": "ya29.a0AfH6SM…",
"expires_in": 3599,
"scope": "openid email profile",
"token_type": "Bearer",
"id_token": "eyJhbGciOiJSUzI1NiIsImtpZ…",
"refresh_token": "1//09abc…"
}
✅ Why PKCE matters even with a client secret — PKCE defeats authorization code interception: even if malware or a malicious app grabs the code from the redirect, it cannot exchange it without the verifier, which never left the legitimate client. Originally designed for mobile and SPAs, PKCE is now recommended for all clients (and is mandatory in the OAuth 2.1 draft).
Step 5 — ID Token Validation
The client must now validate the ID token before trusting a single claim in it. This is non-negotiable. At minimum:
- Signature — verify against Google's public keys from its JWKS endpoint, using the
kidin the header and the expected algorithm (RS256). iss— must behttps://accounts.google.com(oraccounts.google.com).aud— must equal your ownclient_id. This stops a token minted for another app from being replayed at yours.exp/iat— the token must be unexpired (allow small clock skew).nonce— must equal the value sent in Step 1, defeating replay.
Step 6 — Session Creation
Validation is the end of OAuth/OIDC, not the end of login. The protocol has answered "who is this user?" exactly once. The application now establishes its own session — typically by setting a signed, HttpOnly, Secure, SameSite cookie — so the user stays logged in without re-running the flow on every request. The Google tokens have done their job; the app's session takes over from here.
🔎 Discovery makes this configuration-free — You don't hard-code Google's endpoints. OIDC providers publish a discovery document at
https://accounts.google.com/.well-known/openid-configurationlisting the authorization, token, userinfo, and JWKS endpoints plus supported scopes and algorithms. Good client libraries read it automatically.
OAuth vs OpenID Connect
Here is the question that trips up even experienced engineers: if OAuth gives me an access token after the user logs in with Google, why can't I just use that as proof of who they are?
Because an access token is a statement about authorization, not identity. It means "the bearer of this token may access scope X." It says nothing reliable, verifiable, or audience-bound about who the user is — and a Google access token is meant for Google's APIs, not your app.
OpenID Connect (OIDC), finalized in 2014, is a thin identity layer on top of OAuth 2.0. It keeps everything OAuth does and adds the missing identity contract:
- The ID token — a signed JWT whose
audclaim is your client_id and whoseissis the provider. You can cryptographically verify it was issued by Google, for your app, and hasn't been tampered with. - The
nonce— binds the ID token to your specific authorization request, defeating replay and injection. - A standardized
openidscope, UserInfo endpoint, discovery document, and well-defined claims (sub,email,name, …), so every compliant provider behaves the same way.
💡 The one-liner to remember — OAuth 2.0 is for authorization ("what can this app do?"). OpenID Connect is for authentication ("who is this user?"). "Sign in with Google" is OIDC; "let this app read my Google Calendar" is OAuth. Most real flows do both at once.
Conclusion
OAuth 2.0 is about authorization, and login is about authentication — which is precisely why OpenID Connect is required for "Sign in with Google." OIDC adds the signed, audience-bound ID token and the nonce that together let your application prove who just logged in, rather than guessing from an access token never meant for that purpose.
Key takeaways
- OAuth 2.0 = authorization; OpenID Connect = authentication. Use OIDC for login.
- Access token ≠ ID token. Access tokens call APIs; ID tokens identify users. Never swap their jobs.
- Authorization Code + PKCE is the default flow for web and mobile.
- Always validate the ID token: signature (JWKS),
iss,aud,exp, andnonce.- Key users on
sub(Google's stable user id), store tokens out of the browser's reach, and let a vetted OIDC library do the heavy lifting.
Frequently Asked Questions
What is the difference between OAuth 2.0 and OpenID Connect?
OAuth 2.0 is an authorization framework that grants an app scoped access to resources; OpenID Connect (OIDC) is an identity layer built on top of OAuth 2.0 that adds verifiable user authentication via a signed ID token. In short: OAuth answers "what can this app do?" and OIDC answers "who is this user?"
Is "Sign in with Google" OAuth or OpenID Connect?
Both. The underlying flow is OAuth 2.0's Authorization Code Flow with PKCE, and the login/identity portion is OpenID Connect. Requesting the openid scope is what turns an OAuth authorization into an authenticated login that returns an ID token.
What is PKCE, and do I still need it if I have a client secret?
PKCE (Proof Key for Code Exchange) binds the authorization code to the client that requested it, preventing code-interception attacks. Yes — modern guidance (RFC 9700 and the OAuth 2.1 draft) recommends or requires PKCE for all clients, including confidential ones with a secret, because it defends a different attack surface.
What's the difference between an access token and an ID token?
An access token authorizes calls to a resource server (an API) and should be treated as opaque by the client. An ID token is a signed JWT issued to the client that proves the user's identity. Using an access token to determine who a user is — instead of a validated ID token — is a classic security mistake.