Single Sign-On (SSO) with OAuth / OIDC in OAuth 2.0
One login. Every app. Here is exactly how the "Continue with Google" button, the "Sign in with Microsoft" prompt, and the invisible handshake behind them actually work — explained from zero, one brick at a time.
Imagine you arrive at a large office building where fifty different companies rent floors. Instead of getting a brand-new ID badge from every single company just to visit their floor, you swipe one badge at the front desk once, and every floor’s turnstile trusts that badge for the rest of the day. You never hand your badge to any individual company — the front desk vouches for you. That front desk is exactly what an “Identity Provider” does on the internet, and the whole arrangement is called Single Sign-On, built on top of a security protocol called OAuth 2.0 and its identity layer, OpenID Connect (OIDC). By the end of this guide, you will understand this system well enough to explain it to a curious ten-year-old, defend it in a technical interview, and design it correctly in a real production system.
ACore Concepts
Before we can talk about “flows” and “tokens,” we need to agree on what a handful of everyday words mean in this world. Get these right, and everything later becomes easy.
What is Single Sign-On (SSO)?
Single Sign-On means logging in once and then being recognized, without logging in again, by every other application that has agreed to trust that one login. If you have ever opened Gmail, then clicked over to YouTube, Google Docs, or Google Photos in the same browser without typing a password again, you have used SSO. You proved who you are exactly one time; everything else simply asked “has this person already proven themselves to someone I trust?” and got back a “yes.”
Think of a music festival with twenty different stages. You buy one wristband at the entrance gate. Every stage’s security guard just glances at the wristband — they never re-check your ID card, your ticket, or your name. The wristband is proof, issued once by a trusted gate, accepted everywhere inside. SSO is that wristband for websites and apps.
What is OAuth 2.0?
OAuth 2.0 is not a login system by itself. It is a framework for delegated authorization — a way for you to let one application access specific data or perform specific actions on another application’s behalf, without ever handing over your password. When a photo-printing website asks “Allow this app to see your Google Photos?” and you click “Allow,” that is OAuth 2.0 working. The printing website never sees your Google password; Google gives it a limited, revocable token instead.
OAuth 2.0 answers the question “What is this app allowed to do?” (authorization). It does not, by itself, answer “Who is this person?” (authentication). That second question is answered by a companion layer built on top of OAuth 2.0, called OpenID Connect.
What is OpenID Connect (OIDC)?
OpenID Connect is a thin, standardized layer placed directly on top of OAuth 2.0 that adds a reliable way to answer “Who is this person?” It does this by introducing a special token called an ID Token, which is a signed, verifiable statement of identity — essentially a digital, tamper-proof note that says “I, the Identity Provider, confirm this is user 12345, their email is jane@example.com, and I confirmed this at 10:41am.” OIDC is the reason SSO buttons like “Sign in with Google” can exist safely across the entire internet.
Who are you?
Proving identity — handled by OpenID Connect using the ID Token.
What can you do?
Granting limited access to resources — handled by OAuth 2.0 using the Access Token.
Key Vocabulary You Will See Everywhere
A handful of terms recur constantly in this space. We will define each the first time it truly matters, but here is the starter pack.
| Term | Plain-English Meaning |
|---|---|
| Identity Provider (IdP) | The trusted “front desk” that checks your password and vouches for you — e.g., Google, Microsoft Entra ID, Okta, Auth0. |
| Service Provider / Relying Party | The application that trusts the IdP’s vouching instead of running its own login page — e.g., a SaaS tool you sign into with “Sign in with Google.” |
| Access Token | A limited-permission pass an app uses to call an API on your behalf. |
| ID Token | A signed proof of who you are, used by OIDC for authentication. |
| Refresh Token | A long-lived credential used to quietly get new Access Tokens without asking you to log in again. |
| Scope | A specific, named permission being requested, such as profile, email, or calendar.read. |
BArchitecture & Components
SSO is not one machine — it is a small cast of characters that pass carefully-shaped envelopes back and forth. Learn the cast, and every diagram you ever see afterward becomes readable.
The Four Actors
Every OAuth 2.0 / OIDC interaction, no matter how it looks on the surface, is built from exactly four roles working together.
Resource Owner
This is you, the human being. You own the data (your photos, your calendar, your profile) and you get the final say on who is allowed to touch it.
Client Application
The app that wants access — for example, a photo-printing website, a project-management tool, or a mobile app.
Authorization Server (part of the Identity Provider)
The gatekeeper that authenticates you, asks for your consent, and issues tokens. This is the “front desk” — Google’s, Microsoft’s, or a company’s own Okta/Auth0 tenant.
Resource Server
The API that actually holds the data being requested, and that checks incoming Access Tokens before handing anything over.
sequenceDiagram
participant U as Resource Owner (User)
participant C as Client App
participant AS as Authorization Server (IdP)
participant RS as Resource Server (API)
U->>C: Clicks "Sign in with IdP"
C->>AS: Redirects browser to Authorization Endpoint
AS->>U: Shows login + consent screen
U->>AS: Approves
AS->>C: Redirects back with Authorization Code
C->>AS: Exchanges Code for tokens (Token Endpoint)
AS->>C: Returns Access Token + ID Token + Refresh Token
C->>RS: Calls API with Access Token
RS->>C: Returns protected data
The Building-Block Endpoints
Underneath every Identity Provider sit a small, standardized set of URLs. Almost every IdP — Google, Microsoft, Okta, Auth0, Amazon Cognito — exposes the same shapes, which is exactly why the same client library can work against any of them.
Authorization Endpoint
Where the user’s browser is sent to log in and consent.
Token Endpoint
Where the client exchanges a code (or credentials) for tokens, server-to-server.
UserInfo Endpoint
Where an app can fetch more profile details using a valid Access Token (OIDC-specific).
JWKS Endpoint
Publishes the public keys used to verify that a token’s signature is genuine.
Almost every modern IdP publishes a single “discovery document” at a well-known URL, typically /.well-known/openid-configuration. It lists every endpoint above in one JSON file, so a client library can configure itself automatically instead of you hand-typing five different URLs.
CInternal Working
Now we open the hood. This is the part interview panels care about most: not “what is a token” but “walk me through exactly what happens, byte by byte, when I click Sign In.”
The Authorization Code Flow, Step by Step
This is the flow used by essentially every serious web application today, including SPAs and mobile apps once combined with a security add-on called PKCE (explained shortly).
Redirect to Authorize
The client app builds a URL pointing at the Authorization Endpoint, attaching its client_id, the redirect_uri it wants the browser sent back to, the requested scope (e.g. openid profile email), and a random state value used to prevent forgery.
User Authenticates
The browser lands on the IdP’s own login page — the client app never sees the password, because the password field lives entirely on the IdP’s domain, not the client’s.
Consent
If this is the user’s first time, the IdP shows exactly which scopes are being requested (“This app wants to see your email address and profile picture”) and the user approves or denies.
Authorization Code Issued
The IdP redirects the browser back to the client’s redirect_uri with a short-lived, single-use code attached as a query parameter — and the original state value, so the client can confirm nothing was tampered with in transit.
Code Exchange (Back-Channel)
Crucially, this next step happens server-to-server, never in the browser. The client’s backend sends the code, its client_secret (or a PKCE verifier), and the redirect URI to the Token Endpoint.
Tokens Returned
The IdP responds with an Access Token, an ID Token (if OIDC’s openid scope was requested), and often a Refresh Token — all delivered over an encrypted channel that the browser itself never touches.
Session Established
The client verifies the ID Token’s signature and claims, creates its own local session (usually a cookie), and the user is now “logged in” to that application.
Why the Code Exchange Happens Twice, Not Once
A newcomer often asks: why not just hand back the Access Token directly in step 4, in the browser redirect, and skip the extra round trip? The answer is that anything placed in a browser redirect URL can leak — into browser history, server access logs, referrer headers, or a nosy browser extension. By handing back only a short-lived, single-use code in the browser, and requiring the real tokens to be fetched over a separate, authenticated, server-to-server call, the design keeps the valuable, long-lived tokens off the most exposed part of the journey.
The Authorization Code is like a coat-check ticket. Losing the ticket on the sidewalk is annoying but not catastrophic — a stranger who finds it still cannot simply walk out with your coat, because the coat-check counter (Token Endpoint) will only hand over the coat (the real tokens) to someone who also proves they are the right business, usually with a claim stub or password (the client secret).
PKCE — Proof Key for Code Exchange
Mobile apps and single-page apps cannot safely keep a secret at all — anyone can decompile the app or open browser dev tools and read it. PKCE solves this: before starting, the client generates a random secret called a code_verifier, hashes it into a code_challenge, and sends only the hash in step 1. In step 5, it reveals the original code_verifier, and the Authorization Server checks that hashing it produces the same challenge. Anyone who intercepts the authorization code in the middle still cannot redeem it, because they never saw the original verifier.
flowchart LR
A[Client generates random code_verifier] --> B[Hashes it into code_challenge]
B --> C[Sends code_challenge in Authorize request]
C --> D[Authorization Server stores challenge]
D --> E[Client later sends original code_verifier at Token Endpoint]
E --> F{Hash matches stored challenge?}
F -->|Yes| G[Tokens issued]
F -->|No| H[Request rejected]
DData Flow & Lifecycle
Tokens are not permanent objects — they are born, they live for a while, and they die. Understanding that lifecycle is what separates a working SSO integration from a fragile one.
The Shape of Each Token
Most modern Access Tokens and all ID Tokens are formatted as a JWT (JSON Web Token) — three Base64-encoded sections separated by dots: a header (which algorithm was used), a payload of claims (facts like sub for subject/user-id, iss for issuer, exp for expiry), and a signature that proves the token has not been altered since the IdP issued it.
Refreshing Without Re-Login
When an Access Token expires, the client does not force the user to log in again. Instead, it silently sends the Refresh Token to the Token Endpoint and receives a brand-new Access Token (and often a rotated Refresh Token). This is exactly why you can stay “logged in” to an app for weeks even though the underlying Access Token quietly changes every hour behind the scenes.
Best-practice IdPs issue a new refresh token every time one is used, and immediately invalidate the old one. If an old, already-rotated refresh token is ever presented again, that is a strong signal it was stolen and replayed — the IdP can revoke the entire token family instantly.
Session Termination — Single Log-Out (SLO)
Logging out is deceptively hard in SSO, because “logged in everywhere” must eventually mean “logged out everywhere” too. Two common mechanisms exist:
Front-Channel Logout
- The IdP loads a tiny hidden iframe for every relying-party app it knows the user is logged into
- Each app’s logout endpoint fires inside that iframe, clearing its local session
Back-Channel Logout
- The IdP sends a signed “logout token” directly, server-to-server, to each app
- More reliable than iframes, which browsers increasingly block by default
EAdvantages, Disadvantages & Trade-offs
No architecture is free. SSO trades one set of problems for a different, usually smaller, set.
Advantages
- One strong password instead of dozens of weak, reused ones
- Centralized place to enforce multi-factor authentication (MFA) for every app at once
- Instant, company-wide access revocation when an employee leaves
- Fewer password-reset support tickets
- Faster user onboarding — no new account to create per app
Disadvantages / Trade-offs
- The Identity Provider becomes a single point of failure — if it is down, every connected app becomes unreachable
- A compromised IdP account can cascade into every connected system at once
- Adds architectural complexity: redirects, token verification, clock-skew handling
- Cross-domain cookie and browser privacy restrictions (e.g., third-party cookie blocking) complicate some legacy SSO patterns
FSecurity
Because OAuth 2.0 and OIDC sit directly on the path between “internet stranger” and “your private data,” this is the chapter where small mistakes become big headlines.
The State Parameter — Stopping CSRF
The random state value generated in step 1 of the flow and checked again in step 4 exists specifically to stop Cross-Site Request Forgery: an attacker tricking your browser into completing a login flow that was started by them, not you, which could otherwise bind your session to the attacker’s account.
Redirect URI Validation
The Authorization Server must only ever redirect back to a redirect_uri that was pre-registered by the client application, matched exactly, character for character. A loosely-matched redirect URI (allowing wildcards or partial matches) is one of the single most common real-world OAuth vulnerabilities, because it lets an attacker redirect the authorization code straight to a server they control.
Open redirect chains are the classic exploit: an attacker finds any endpoint on the legitimate client domain that itself redirects onward based on a query parameter, registers that as their “exact match” redirect_uri, and rides it out to their own server, code in hand.
Token Storage on the Client
| Storage Location | Risk |
|---|---|
| localStorage (browser) | Readable by any JavaScript on the page — vulnerable to XSS token theft |
| HttpOnly, Secure cookie | Not readable by JavaScript at all, but needs CSRF protections since cookies are sent automatically |
| In-memory (JS variable) | Safer against theft but lost on page refresh, requiring a silent re-auth |
Always Verify the ID Token Properly
A client must never simply trust an ID Token because it “looks right.” It must check the cryptographic signature against the IdP’s published public keys, confirm the iss (issuer) matches the expected IdP, confirm the aud (audience) matches this specific client’s own client ID, and confirm the exp (expiry) has not passed. Skipping any one of these checks has historically allowed forged or reused tokens to be accepted as genuine.
Pattern
Using the Access Token itself as proof of user identity inside your own application logic.
Why It Fails
Access Tokens are meant for calling APIs, are often opaque (not even readable), and are not guaranteed to carry any user-identifying claims at all. Identity must always come from a verified ID Token, never inferred from the Access Token.
GMonitoring, Logging & Metrics
An SSO system that nobody watches is a system nobody actually trusts yet — visibility is what turns “it should be secure” into “we can prove it is secure.”
Failed Login Rate
A spike often signals credential-stuffing attacks aimed at the IdP.
Token Issuance Latency
Slowness at the Token Endpoint directly stalls every connected application’s login.
Refresh-Token Reuse Alerts
Detects a rotated, already-used refresh token being replayed — a theft indicator.
Consent Grant Volume
Tracks how often new scopes are approved, useful for spotting over-permissioned apps.
What to Log, Precisely
Every authorization request, token issuance, token refresh, and token revocation event should be logged with a correlation ID, the client ID involved, the scopes granted, and a timestamp — but never the token values themselves, and never raw passwords. Logs are a prime attacker target, so they must be treated as sensitive data in their own right.
Production Practice: Anomaly-Based Alerting
Large-scale identity providers commonly flag “impossible travel” — a login from New York followed nine minutes later by a login from Singapore using the same account — and automatically step up authentication or block the session pending verification.
HDesign Patterns & Anti-patterns
Certain shapes of solution appear again and again across every serious identity system. Recognizing them saves you from reinventing broken wheels.
Pattern: Backend-for-Frontend (BFF) Token Handling
Instead of letting a single-page application hold tokens directly in the browser, the SPA talks only to its own lightweight backend, which itself holds the tokens server-side and issues the SPA a simple, HttpOnly session cookie. This removes the entire class of browser-based token theft.
Pattern: Federation Broker / Identity Hub
Large enterprises rarely connect every application directly to every possible IdP. Instead, they place one central broker (like Auth0, Okta, or a homegrown identity gateway) in the middle, which itself federates out to Google, Microsoft, or a corporate Active Directory — so each individual application only ever needs to integrate with one broker, not dozens of providers.
flowchart TB
subgraph Apps
A1[App A]
A2[App B]
A3[App C]
end
Broker[Identity Broker]
subgraph Providers
P1[Google]
P2[Microsoft Entra ID]
P3[Corporate AD]
end
A1 --> Broker
A2 --> Broker
A3 --> Broker
Broker --> P1
Broker --> P2
Broker --> P3
Pattern
The Implicit Flow — returning tokens directly in the URL fragment of a browser redirect, with no code exchange step at all.
Why It Fails
Tokens end up exposed in browser history and referrer data with no server-side exchange to protect them, and they cannot be refreshed safely. It has been formally deprecated in favor of the Authorization Code Flow with PKCE for every client type, including SPAs.
Pattern: Scope Minimization
Request only the exact scopes needed for the feature being built right now, not every scope you might ever want. A calendar-reading feature should request calendar.readonly, not calendar with full write access “just in case.”
IBest Practices & Common Mistakes
This is the checklist experienced architects run through before an SSO integration ever reaches production.
Always use PKCE
Even for confidential clients — it adds protection at essentially zero cost.
Validate every claim
Issuer, audience, expiry, and signature — every single time, no shortcuts.
Hardcode a single IdP
Build against the OIDC standard so switching providers later doesn’t mean a rewrite.
Store tokens in localStorage
Prefer HttpOnly cookies or a BFF pattern to reduce XSS blast radius.
Common Mistake: Confusing “Logged Out of App” with “Logged Out of IdP”
Clearing a local session cookie only logs the user out of that one application. The IdP session may still be fully active, meaning a fresh “Sign in with Google” click could silently re-authenticate the user without ever showing a password prompt — which surprises users who assumed they had fully logged out.
Common Mistake: Trusting Client-Side Role Checks
A scope or claim inside a token tells you what a user is allowed to request — it must still be independently checked on the server for every sensitive action. Never let the frontend’s decision to hide a button stand in for a real backend authorization check.
JReal-World & Industry Examples
Theory becomes concrete once you see the names you already know using exactly the mechanics above.
Google Workspace
Signing into Gmail once grants seamless access to Docs, Sheets, Drive, and YouTube’s logged-in features — a textbook SSO deployment built entirely on OIDC ID Tokens issued by Google’s own Authorization Server.
Microsoft Entra ID (formerly Azure AD)
Enterprises use it as the central IdP for hundreds of internal and third-party SaaS applications simultaneously, enforcing one company-wide MFA policy from a single control plane.
Slack “Sign in with Google/Apple”
Slack acts as a Relying Party, federating identity out to a user’s chosen IdP rather than maintaining yet another standalone password for every workspace member.
Spotify’s Third-Party App Ecosystem
Playlist-generator and music-analysis apps use OAuth 2.0 scopes (like read-only playlist access) to interact with a user’s Spotify account without ever seeing their Spotify password — a clean demonstration of delegated authorization at consumer scale.
KFrequently Asked Questions
LSummary and Key Takeaways
Carry These Forward
- SSO lets a user log in once and be trusted across many applications, built on top of OAuth 2.0 and OpenID Connect.
- OAuth 2.0 handles delegated authorization — what an app is allowed to do — never authentication by itself.
- OpenID Connect adds the missing identity layer through the signed ID Token.
- The Authorization Code Flow with PKCE is the modern, standard flow for every client type, web or mobile.
- Tokens are short-lived by design; Refresh Tokens quietly extend sessions without repeated logins.
- Security depends on strict
redirect_urimatching, thestateparameter, and full ID Token verification — never trust a token you have not cryptographically checked. - Real systems concentrate trust in the Identity Provider deliberately — and defend that one point far more heavily than any individual app ever could alone.