HomeProjectsBlogContact

OAuth and Social Login Explained (Without the Jargon)

"Sign in with Google" looks like one button but involves redirects, codes, tokens and a few important security checks. How OAuth 2.0 and OpenID Connect work, and how to implement them safely.

OAuth and Social Login Explained (Without the Jargon)

"Sign in with Google," "Continue with GitHub," "Log in with Apple." Users love social login because there's no new password to remember. Developers love it because there's no password to store. But the protocol underneath, OAuth 2.0, has a reputation for being confusing. Let's untangle it.

OAuth vs OpenID Connect

These two get mixed up constantly:

  • OAuth 2.0 is about authorization: letting an app access something on your behalf. "Allow this app to read your calendar."
  • OpenID Connect (OIDC) is a layer on top of OAuth for authentication: proving who you are. It adds an ID token containing the user's identity.

"Sign in with X" is OIDC (or a provider's OAuth flow used for login). Accessing a user's files or calendar via API is OAuth.

The players

  • The user (resource owner)
  • Your app (the client)
  • The provider (authorization server), like Google or GitHub
  • The API holding the user's data (resource server), if you're accessing data

The authorization code flow with PKCE

This is the recommended flow for web apps, mobile apps and single-page apps:

  1. User clicks "Sign in with Provider." Your app redirects them to the provider's authorization URL with:
    • client_id (identifies your app)
    • redirect_uri (where to send them back)
    • scope (what you're asking for, like openid email profile)
    • state (a random value to prevent CSRF)
    • code_challenge (for PKCE, explained below)
  2. User logs in at the provider and approves the request. Your app never sees their password.
  3. Provider redirects back to your redirect_uri with a short-lived authorization code and the same state.
  4. Your server exchanges the code for tokens by calling the provider's token endpoint, including the code_verifier.
  5. You receive tokens: an access token, possibly a refresh token, and with OIDC an ID token identifying the user.
  6. Your app creates its own session for the user. (Sessions vs JWTs.)

Why PKCE matters

PKCE (Proof Key for Code Exchange, pronounced "pixie") protects against someone intercepting the authorization code. Your app creates a random secret (code_verifier), sends a hashed version (code_challenge) at the start and the original at the exchange. An attacker with only the code can't complete the exchange. It's now recommended for all clients, not just mobile apps.

Security checks you must not skip

  • Validate state. Compare the returned state with the one you stored. If it doesn't match, reject the login. This prevents login CSRF.
  • Register exact redirect URIs. Never allow wildcards or open redirects; a loose redirect URI lets attackers steal codes.
  • Exchange codes on the server and keep your client secret there, never in frontend code. (Environment variables.)
  • Validate the ID token: signature, issuer, audience (your client ID), expiry and nonce. A good library does this for you.
  • Request minimal scopes. Only ask for what you need. Users notice, and less access means less risk.
  • Don't use the implicit flow. It returned tokens directly in the URL and is considered outdated.

Linking accounts carefully

A user might sign up with email and password, then later click "Sign in with Google" using the same email. Should those be the same account?

  • Only link automatically if the provider confirms the email is verified.
  • Safer still: ask the user to log in to their existing account first, then link the provider.
  • Store provider identities in a separate table (user_id, provider, provider_user_id), so one user can have several login methods.

Use the provider's stable user ID, not the email, as the identifier. Emails can change.

Use a library or auth service

You rarely need to implement OAuth from scratch, and you shouldn't. Mature options exist for every stack: framework auth libraries (for Next.js, Laravel, Django, Rails and others), or hosted authentication services that handle providers, sessions, MFA and account linking. They get the subtle details right.

What you still own: deciding what happens after login, protecting your own routes and checking permissions. (Security checklist.)

Testing

  • Create separate OAuth app registrations for development, staging and production, each with its own redirect URIs.
  • Test denying permission, cancelling midway and logging in with an account whose email isn't verified.
  • Test what happens when a user revokes your app's access at the provider.

FAQ

What is the difference between OAuth and OpenID Connect?

OAuth 2.0 handles authorization (granting access to resources). OpenID Connect builds on it to handle authentication, adding an ID token that tells your app who the user is.

What is PKCE in OAuth?

A security extension where the client sends a hashed secret at the start of the flow and the original secret when exchanging the code, so an intercepted authorization code is useless on its own.

Is social login secure?

Yes, when implemented correctly with the authorization code flow, PKCE, state validation, exact redirect URIs and ID token validation. Using a well-maintained library makes this much easier.

Keep reading

More from the workbench

All articles →