Introduction: The Magic Login Button
You're on a website. You see "Login with Google" or "Login with GitHub." You click it. Boom — you're logged in. No passwords to remember, no email verification waiting. Just... magic?
But how does this actually work? Let's take a journey together and understand what happens behind that simple button click.
Why Google, GitHub, Facebook Are Used

First question: Why do we always see Google, GitHub, Facebook, X (Twitter), or Microsoft? Why not any random website?
The answer is simple: they have massive user bases. Almost everyone has a Google account. Many developers have GitHub accounts. These companies are famous merchants of identity because they already store information about billions of users.
Think about it — your information is already sitting in Google's servers, tied to your email ID. So why should you sign up on every new website, verify your email again and again? It's exhausting.
That's the problem these providers solve.
Where Our Information Already Lives
Here's the key insight: you're already logged into your browser.
Whether it's Chrome, Firefox, or Safari, you've probably logged into Google or GitHub on your mobile or desktop. Your authentication already exists. You've already proved who you are to these providers.
So new companies thought: "Why not leverage this? Why make users create new accounts when they can just use what they already have?"
And that's how this story begins.
Registering a Website as a Client
Let's pause here. Before any website can offer "Login with Google," they need to register themselves.
Here's what happens:
A company (let's say Canva) goes to Google and says: "Hey, I want to use your authentication service." They register their website as a client with details like:
- Application type: Is it a website or a native mobile app?
- Name: What's the application called?
- URL: Where does it live?
- Redirect URI: Where should Google send users back after login?
In return, Google gives them:
- client_id: A unique identifier (like a username for the website)
- client_secret: A password that authenticates the client to Google
These credentials are crucial. They prove to Google that the request is coming from a legitimate registered client.
Clicking "Login with Provider"
Alright, now we're at the moment you click "Login with Google."
What happens?
The website (client) redirects you to Google's website. This isn't just a simple redirect though. The client sends several important pieces of information along with you.
Authentication and User Consent
You land on Google's page.
First, Google authenticates you. If you're not already logged in, they'll prompt you to enter your email and password.
Once you're authenticated, Google shows you something like:
"Canva.com is asking for your email, name, and profile picture. Allow or deny?"
This is the authorization step. You're deciding what information the client can access.
If you click "Allow," Google prepares to share that information with the client. But what happens at a deeper layer?
What Is Sent During Redirect (High-Level)
When the client redirected you to Google, they sent several parameters. Let me break them down in simple terms:
- state: A random token for CSRF protection. It makes every request unique so hackers can't forge requests.
- scope: What information does the client want? Email? Name? Profile picture?
- client_id: Who is asking? This authenticates the client.
- redirect_uri: Where should Google send the user back? Google checks this matches what was registered.
-
response_type: What kind of response does the client want? Usually
authorization_code. - nonce: A random value to prevent replay attacks (we'll explain this later).
- code_challenge and code_challenge_method: Extra security (PKCE — we'll get to this).
- prompt: Should Google ask for authentication every time, or trust existing sessions?
- access_type: Should Google provide a refresh token? (Offline vs online access)
Google checks all these parameters, authenticates you, and asks for your consent.
Authorization Code and State Check
Once you authorize, Google redirects you back to the client's website. But they don't send your information directly.
Instead, they send:
- authorization_code: A temporary code
- state: The same state token sent earlier
The client's server receives this callback. First thing they do? Check the state token.
If the state matches what they sent earlier, it's a valid request. If not, someone's trying to attack them (CSRF attack).
Now they have an authorization code. But this code alone isn't enough.
Why We Don't Use response_type=token
You might wonder: "Why not just send the access token directly?"
Some systems allow response_type=token, where the provider sends the access token immediately in the URL.
This is not secure.
Why? Because the token would be visible in the browser's address bar, in logs, in history. Anyone with access to the browser could steal it.
That's why the secure approach uses authorization_code instead. The real tokens are exchanged server-to-server, hidden from the browser.
Server-to-Server Token Exchange
Now the magic happens behind the scenes.
The client's server makes a POST request to Google's token endpoint. This happens server-to-server, completely hidden from the user's browser.
They send:
-
grant_type: Set to
authorization_code(explains how they're authenticating) - client_id: Their identity
- client_secret: Their password (for authentication)
- redirect_uri: For validation
- code: The authorization code they just received
- code_verifier: Extra security (PKCE — hold on)
Google checks everything. If it's all valid, they respond with a JSON containing the real tokens.
PKCE and Why It Exists
Let's pause here. What if a hacker somehow steals the authorization code?
Think about it. The code is sent via redirect in the URL. If someone intercepts it, they could potentially exchange it for tokens.
That's where PKCE (Proof Key for Code Exchange) comes in.
Here's how it works:
-
Before the redirect, the client generates a random string (32 bytes or more). This is the
code_verifier. - They hash it using SHA256. This becomes the
code_challenge. - They send the
code_challengeandcode_challenge_methodto Google during the initial redirect.
Google stores this hash.
- Later, during the token exchange, the client sends the original
code_verifier. - Google hashes it with the same method and compares it to the stored
code_challenge.
If they match, the request is valid. If not, someone stole the code.
This makes the flow nearly unbeatable.
Tokens We Receive
If everything checks out, Google responds with JSON containing:
- access_token: Used to access user information
- refresh_token: Used to get new access tokens when they expire
- scope: What information is included
- id_token: A JWT token containing user information (only with OpenID Connect)
Many providers like GitHub don't use OpenID Connect, so they might not send an id_token. We'll talk about that in a moment.
ID Token Verification
If we receive an id_token, we need to verify it.
Why? Because it's a JWT (JSON Web Token), and we need to ensure it's actually from Google and hasn't been tampered with.
Here's the process:
- Get Google's public JWKS (JSON Web Key Set) URI
- Verify the signature on the JWT using the public key
- Check the nonce inside the token
Remember that nonce we sent during the initial redirect? It comes back inside the id_token.
We check if the nonce matches what we sent. If it does, this token was created in response to our specific request. This prevents replay attacks — someone can't reuse an old token.
Now we have verified user information.
Getting User Info When OpenID Is Not Used
What if the provider doesn't support OpenID Connect? (Like GitHub)
No problem. We use the access_token.
We make a simple GET request to the provider's user info endpoint with the access token in the Authorization header:
Authorization: Bearer [access_token]
The provider responds with the user's email, name, and other information we requested.
Final Login: User Creation and Session
Now we have everything:
- User's email
- User's name
- Verified information
The server does a few final steps:
- Create or get user: Check if this user already exists in our database. If yes, log them in. If no, create a new account.
- Account linking: Link this provider account to our user record.
- Store tokens: Save the access token and refresh token securely.
- Session creation: Create a session for the user.
And... done! The user is logged in.
Closing Thoughts
We've journeyed through a lot:
- Why providers like Google exist
- How websites register as clients
- What happens during redirect
- Security measures like state, nonce, and PKCE
- Token exchange behind the scenes
- Verification and user creation
This flow might seem complex, but each piece exists for a reason — mostly security.
I've touched on many concepts here. There's even more depth to explore (like the full RFC 6749 specification at https://datatracker.ietf.org/doc/rfc6749/), but this gives you the journey from click to login.
The Flow (Simplified)
User Client (Canva) Provider (Google)
| | |
|--Click "Login" --------->| |
| | |
|<--Redirect with params---| |
| (state, scope, client_id, nonce, code_challenge) |
| |
|--Redirected to Google---------------------------------->|
| |
|<--Authentication & consent screen-----------------------|
| |
|--User approves----------------------------------------->|
| |
|<--Redirect with code & state----------------------------|
| |
|--Return to client-------------------------------------->|
| | |
| |--POST request--------------->|
| | (code, client_id, |
| | client_secret, |
| | code_verifier) |
| | |
| |<--Tokens (access, refresh, |
| | id_token)--------------- |
| | |
| |--Verify id_token------------>|
| | or fetch user info |
| | |
|<--User logged in---------| |



Top comments (0)