You are installing a new app — say, an exam-prep app that tracks your CBSE Class 9 mock test scores. On the sign-up screen there are two buttons: "Sign up with email and password" and "Continue with Google." You tap the Google button. A Google screen pops up, already showing your name and photo, and asks: "ExamPrep wants to: view your email address and basic profile info. Allow?" You tap Allow. Two seconds later you are inside the app, logged in, with your Google display picture already in the corner.
Stop and ask the question this chapter is built around: did the ExamPrep app just receive your Gmail password? Most students' first instinct is "sort of, yes — how else would it know it's me?" That instinct is wrong, and the mechanism that makes it wrong — a protocol called OAuth 2.0 — is one of the most important pieces of security engineering running on the internet today. Almost every "Continue with Google / Facebook / GitHub" button you have ever tapped is OAuth2 at work.
The old, dangerous way — and why it had to die
Before OAuth2 became standard (it was published by the IETF as RFC 6749 in 2012, though earlier drafts existed from 2007), a third-party app that wanted to read your contacts from another service, say your email provider, would simply ask you to type your email username and password directly into its own login form. This pattern is sometimes called the "password anti-pattern," and it has two serious problems.
First, the third-party app now has your real password. It might store it insecurely, and if that app is ever breached, the attacker doesn't just get access to the app — they get your actual email password, which probably unlocks your email, and because people reuse passwords, possibly your banking and school portal logins too.
Second, and just as important: a password is all-or-nothing access. There is no way to type in "let this app read my name and photo, but not send emails or delete my account." Once the app has your password, it can do anything you can do — because as far as the email server is concerned, a request that arrives with the correct password is you.
Think of it like this: you hire someone to valet-park your car for twenty minutes. The old way is like handing them your entire keyring — car key, house key, office key, locker key — because that's the only ring you own. The valet only needed the car key, but now they could, in principle, walk into your house. OAuth2 is the security engineer's answer: cut a separate key that starts the car and nothing else, and hand over only that one, for exactly the time needed, with the ability to invalidate it afterward without changing every other lock in your life.
Correcting a common misconception: OAuth2 is not "the login system"
Here is a mistake that even working programmers make, so it is worth stating precisely and early: OAuth2 is an authorization protocol, not an authentication protocol. These are different questions.
- Authentication answers: "Who is this person?" (Prove you are Ananya.)
- Authorization answers: "What is this person/app allowed to do?" (Ananya's app may read her email address, nothing more.)
OAuth2, on its own, was designed purely to solve the second problem: letting Ananya grant the ExamPrep app limited, revocable permission to fetch specific data from Google, without Google ever having to trust ExamPrep with Ananya's password. Strictly speaking, plain OAuth2 does not even guarantee that the human clicking "Allow" is who they claim to be in a portable, verifiable way — it just proves that someone logged into the Google account authorized this access.
What actually powers the "Continue with Google" identity check — the part that lets ExamPrep say "this user is verifiably ananya.sharma@gmail.com" — is a thin identity layer built on top of OAuth2 called OpenID Connect (OIDC), standardized in 2014. OIDC adds one crucial extra artifact to the OAuth2 exchange: a signed ID Token containing verified identity claims (who you are), separate from the Access Token (what data the app can fetch). In everyday conversation people say "we use OAuth2 for login," and that's close enough for casual use — but for a CBSE Computer Science answer, or for an actual engineering decision, the precise statement is: social login uses OAuth2 for delegated authorization and OpenID Connect for authentication, running together in a single flow. This chapter covers the OAuth2 mechanics in depth, since OIDC's ID Token is really just an OAuth2 access-token exchange with one extra token attached.
The four roles you must be able to name
Every OAuth2 conversation has exactly four participants. Confusing them is the single most common source of errors when students first learn this topic, so fix the vocabulary before anything else, using our ExamPrep example:
- Resource Owner — the human who owns the data. In our story, this is you, Ananya.
- Client — the application requesting access. This is the ExamPrep app. Note: "Client" here does not mean your phone; it means the ExamPrep company's software (its app and its backend server).
- Authorization Server — the system that authenticates the Resource Owner and issues tokens. This is Google's login and consent system (accounts.google.com).
- Resource Server — the system that actually holds the protected data and accepts tokens as proof of permission. This is Google's profile/People API server.
In Google's and most large providers' case, the Authorization Server and Resource Server are operated by the same company, so students often merge them into one mental box called "Google." Keep them conceptually separate anyway — in some systems (for example, a school's own app suite) the server that logs you in and the server that stores your marks can genuinely be two different machines with two different jobs.
Worked example: scope is a subset, not the whole account
Before tracing the full flow, let's fix the idea of a scope with simple arithmetic, since this is the single most important safety property of OAuth2.
Imagine Google offers 8 possible permission categories for a third-party app to request: read email address, read name/photo, read full mail contents, send mail, read contacts, read calendar, read Drive files, and delete the account. Call this full set of capabilities A, where |A| = 8.
When ExamPrep sends its authorization request, it doesn't ask for A. It asks for a specific subset, written as a space-separated scope string:
scope=email profile
That's a request for a subset S = {email, profile}, so S ⊂ A and |S| = 2. As a fraction of total account capability, that's 2/8 = 0.25, i.e. the app is asking for access to only 25% of what your Google account can theoretically do — and it cannot silently expand that later. If ExamPrep later wants calendar access too, it must send a brand-new authorization request with an updated scope, and you get shown a fresh consent screen listing exactly the new permission.
This is also why the token that eventually gets issued is dangerous only in a bounded way: even if an attacker somehow stole ExamPrep's access token, the token itself only unlocks the resources inside S. It cannot read your mail or delete your account, because it was never issued with those rights in the first place — a direct, checkable consequence of restricting the request to |S| = 2 out of |A| = 8 rather than handing over the full set. This is called the principle of least privilege, and OAuth2's scope mechanism is how that principle gets enforced in code, not just in policy documents.
The Authorization Code Flow, step by step
The most common and most secure OAuth2 pattern for a web or mobile app doing social login is called the Authorization Code Flow. Walk through it with ExamPrep and Google as the concrete example. Read each step and ask "why not skip this step?" — the answer to that question is almost always "because skipping it creates a specific attack."
Step 1 — You click "Continue with Google." The ExamPrep app, running in your browser or phone, prepares a request. It does not ask you for any Google credentials itself.
Step 2 — Your browser is redirected to Google's Authorization Server, carrying a URL that looks like this:
https://accounts.google.com/o/oauth2/v2/auth?
client_id=examprep-8841.apps.googleusercontent.com&
redirect_uri=https://examprep.in/auth/callback&
response_type=code&
scope=email%20profile&
state=x8fQ2mZp9kLwT4vR
Notice this request happens entirely between your browser and Google — ExamPrep's server is not even involved in this step, which is exactly the point: your credentials will never pass through ExamPrep's hands. The state parameter is a random, unguessable string that ExamPrep generated and will check again at the end; hold that thought, we'll need it in Step 4.
Step 3 — Google authenticates you and shows a consent screen. You log in directly on Google's own page (typing your real password only into a page whose address bar says accounts.google.com — never into ExamPrep). Google then shows exactly the scopes ExamPrep requested — "view your email address," "view your basic profile info" — and you click Allow or Cancel. This is the only moment your actual Google credentials are ever typed anywhere.
Step 4 — Google redirects you back with a one-time authorization code. Your browser is sent back to ExamPrep's registered redirect_uri:
https://examprep.in/auth/callback?
code=4/0AY0e-g7dXpQmN...&
state=x8fQ2mZp9kLwT4vR
ExamPrep's server now compares the state value it receives to the one it generated in Step 2. If they don't match, it refuses to continue. This is the defense against a real attack called login CSRF: without state, an attacker could trick you into completing an authorization flow that was actually initiated by the attacker's own browser session, silently linking your Google identity to an attacker-controlled ExamPrep account. Matching state proves the code arriving now belongs to the same browser session that started the request.
Also notice: what arrives in the browser's URL bar (and browser history, and possibly server logs) is only a short-lived, single-use code — not a usable access token. That is deliberate.
Step 5 — ExamPrep's backend server exchanges the code for tokens. This step happens server-to-server, not through your browser, using a direct HTTPS call:
POST https://oauth2.googleapis.com/token
Content-Type: application/x-www-form-urlencoded
code=4/0AY0e-g7dXpQmN...&
client_id=examprep-8841.apps.googleusercontent.com&
client_secret=GOCSPX-9fT2rL...&
redirect_uri=https://examprep.in/auth/callback&
grant_type=authorization_code
Here is the second reason this two-step "code, then exchange" dance exists rather than handing over a token directly in Step 4: the exchange requires client_secret, a credential known only to ExamPrep's server, never shipped to your browser or phone. Even if an attacker intercepted the authorization code from your browser's history, they cannot redeem it for anything without also possessing ExamPrep's server-held secret. The browser only ever handles the low-value, single-use code; the high-value secret and the resulting tokens stay server-side.
Step 6 — Google responds with the tokens, typically:
{
"access_token": "ya29.a0AfH6...",
"id_token": "eyJhbGciOiJSUzI1NiIs...",
"expires_in": 3600,
"token_type": "Bearer"
}
access_token is what ExamPrep uses to call Google's APIs on your behalf (the OAuth2 part). id_token is the OpenID Connect ID Token proving your verified identity (the authentication part). expires_in is a plain arithmetic fact: this token dies 3600 seconds after issue. If it was issued at 10:15:00 IST, simple addition tells you it stops working at 10:15:00 + 3600s = 11:15:00 IST. Short expiry is another safety measure — a leaked token is only dangerous for a bounded window, after which ExamPrep must silently use a longer-lived refresh token to get a new one, without bothering you again.
Step 7 — ExamPrep calls Google's Resource Server using the access token to fetch your profile:
GET https://www.googleapis.com/oauth2/v3/userinfo
Authorization: Bearer ya29.a0AfH6...
Step 8 — Google returns your profile JSON, and ExamPrep creates its own local session for you (usually a cookie), completing the login. From this point on, ExamPrep never needs to talk to Google again until the token needs refreshing.
Diagram: the full round trip
Worked example: what an ID token actually contains
The id_token from Step 6 is not a random string — it's a JWT (JSON Web Token), and understanding its structure demystifies a lot of what "signed token" means in security generally. A JWT always has exactly three parts separated by dots: header.payload.signature.
Take a simplified header and payload as JSON:
header = {"alg":"RS256","typ":"JWT"}
payload = {"sub":"2004829","name":"Ananya Sharma","email":"ananya.sharma@gmail.com"}
Each of these JSON objects is run through a simple, reversible text-encoding function called Base64URL — it is not encryption and hides nothing; it only repackages text into a URL-safe character set. Encoding the two objects above (this is the exact, verified output, not an approximation) gives:
header_b64 = eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9
payload_b64 = eyJzdWIiOiIyMDA0ODI5IiwibmFtZSI6IkFuYW55YSBTaGFybWEiLCJlbWFpbCI6ImFuYW55YS5zaGFybWFAZ21haWwuY29tIn0
Notice the encoding is a genuine function: feed it the exact JSON text and it always produces the exact same output string — there is nothing random or secret about it, which is why anyone (including you) can decode a JWT's header and payload just by reversing Base64URL, no key required. Try it: any base64 decoder will turn eyJhbGciOiJSUzI1NiIs... straight back into {"alg":"RS256",...}. The token is readable by design.
The final piece, appended after a third dot, is the signature — computed by Google's Authorization Server using a private cryptographic key that only Google possesses:
eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIyMDA0ODI5IiwibmFtZSI6IkFuYW55YSBTaGFybWEiLCJlbWFpbCI6ImFuYW55YS5zaGFybWFAZ21haWwuY29tIn0.<signature-bytes>
This is the part that actually matters for security. Since the header and payload are just plainly readable text, anyone could type up a fake payload claiming "email":"principal@school.edu" — but they cannot produce a matching signature for it, because computing a valid RS256 signature requires Google's private key, which never leaves Google's servers. ExamPrep's server checks the signature using Google's freely published public key (a separate, non-secret key mathematically paired with Google's private one). If even a single character of the header or payload is changed after signing, the signature check fails and ExamPrep rejects the token outright. So the trust in an ID token doesn't come from the content being hidden — it's fully readable — it comes from the content being provably unforgeable by anyone except Google.
A second misconception worth naming: "the redirect can go anywhere the app wants"
Students who read Step 4 sometimes assume ExamPrep can set redirect_uri to whatever URL it likes at request time. It cannot. When ExamPrep first registers itself as a Google OAuth2 client (a one-time developer setup step, before any of this flow runs), it must list every exact redirect_uri it will ever use. Google's Authorization Server checks the redirect_uri in Step 2's request against that pre-registered list and refuses to proceed if it doesn't match exactly.
This matters because without it, an attacker could construct their own malicious link using ExamPrep's real client_id but pointing redirect_uri at an attacker-controlled server. If Google accepted arbitrary redirect URIs, a victim who clicked that link and approved the consent screen (which would still correctly say "ExamPrep," since the client_id is genuine) would have their authorization code delivered straight to the attacker's server instead of ExamPrep's. Pre-registration closes this off: no matter what URL an attacker puts in the request, Google will only ever redirect to an address ExamPrep's developers configured in advance.
Why the Authorization Code Flow replaced the older Implicit Flow
Early OAuth2 deployments (especially for JavaScript-only apps with no backend server) used something called the Implicit Flow, where the access token was returned directly in the browser redirect URL in Step 4, skipping the code-exchange step entirely — because such apps had no server, and thus no client_secret to protect. This is now considered obsolete and is explicitly discouraged by the OAuth 2.0 Security Best Current Practice (published by the IETF working group). The problem: a token sitting in a URL fragment can leak through browser history, proxy logs, and the "Referer" header of any subsequent request, and unlike an authorization code, a leaked access token is immediately usable — there is no second secret gate protecting it. Modern practice uses the Authorization Code Flow everywhere, adding a technique called PKCE (Proof Key for Code Exchange) for apps without a backend server or client_secret, where the app generates a random secret locally at the start of the flow and proves it holds that same secret again during the code exchange — achieving the same "only the real requester can redeem the code" guarantee without needing a permanently stored client_secret.
Revocation: the advantage a password can never give you
Return to the valet-key analogy. Because ExamPrep only ever holds a scope-limited, expiring token — never your actual password — you can open your Google Account's "Third-party apps with account access" settings page at any time and revoke ExamPrep's access with one click, instantly, without changing your Google password at all. Every other app you've connected keeps working exactly as before. This is impossible under the old password-sharing model: if you'd handed ExamPrep your actual password and wanted to cut it off, your only option was to change the password everywhere, breaking every legitimate session simultaneously. Individually revocable, individually scoped access is the entire point of building OAuth2 instead of just trusting apps with credentials directly.
Active recall
- A friend says, "OAuth2 is just how Google checks your password for other apps." Identify exactly what is wrong with this sentence, using the authentication-versus-authorization distinction.
- In the Authorization Code Flow, why is the authorization code exchanged for a token using a separate server-to-server call (Step 5) instead of Google just returning the access token directly in the Step 4 redirect?
- An app requests
scope=profileonly (notemail). If its access token is later stolen, list two things the attacker still cannot do with it, and explain why the scope mechanism guarantees that. - What specific attack does the
stateparameter defend against, and what does ExamPrep's server do with thestatevalue it receives in Step 4? - Explain why a JWT's header and payload being "readable by anyone" is not itself a security flaw, using the role of the signature.
- Why must
redirect_uribe registered in advance rather than supplied freely at request time?
Summary
OAuth2 solves a precise problem: letting you grant a third-party app narrow, revocable, inspectable access to specific parts of your account on another service, without ever handing that app your password. It is fundamentally an authorization framework — the identity-proving "login" behaviour of the social-login button actually comes from OpenID Connect's ID Token layered on top. The four roles — Resource Owner, Client, Authorization Server, Resource Server — map onto you, the third-party app, and the two halves of the provider (Google, in our examples). The Authorization Code Flow's extra steps — a short-lived, single-use code exchanged server-side for tokens, a checked state parameter, a pre-registered redirect_uri, and a signed, expiry-limited token — are not bureaucratic overhead; each one closes a specific, real attack (credential exposure, login CSRF, redirect hijacking, token forgery, and indefinite token lifetime, respectively). Scopes enforce the principle of least privilege as a hard technical limit, not just a policy promise, and revocability means access can be cut instantly without disturbing anything else tied to your account. The next time you tap "Continue with Google," you now know exactly which of the nine steps in that diagram just ran, and why each one exists.