Skip to content

OAuth Basics for Node.js

"Sign in with Google" and similar buttons are powered by OAuth 2.0. This lesson explains the underlying flow conceptually and how to implement it in a Node.js app using Passport.js.

What Problem Does OAuth Solve?

OAuth 2.0 lets a user grant your application limited access to their account on another service (Google, GitHub, etc.) without ever sharing their password with your app directly. Instead, the user authenticates with the provider, the provider asks for their consent, and your app receives a token proving that consent, scoped to specific permissions.

The most common flow for web apps is the "Authorization Code" flow: your app redirects the user to the provider, the provider redirects back with a temporary code, and your server exchanges that code (server-to-server, using a client secret) for an access token.

// Simplified authorization code flow
// 1. Redirect the user to the provider
res.redirect(
  `https://accounts.google.com/o/oauth2/v2/auth?client_id=${clientId}&redirect_uri=${redirectUri}&response_type=code&scope=email profile`
);

// 2. Provider redirects back to your callback with ?code=...
// 3. Your server exchanges the code for tokens (server-to-server call)
// 4. Your server creates a session or JWT for the now-authenticated user

The user's password never touches your server at any point, they authenticate entirely on the provider's own login page.

Key OAuth Terms

Client       - your application, requesting access
Resource Owner - the user granting access
Authorization Server - the provider (Google, GitHub, etc.)
Access Token  - proof of granted, scoped access
Scope         - the specific permissions requested (email, profile, ...)
  • Your app never sees or stores the user's password on the third-party provider.
  • "Scopes" define exactly what your app is allowed to access (e.g. just email and profile, not full account control).
  • Access tokens from OAuth providers are typically short-lived and can be refreshed.
  • The authorization code exchange step happens server-to-server, using a confidential client secret.

OAuth Concepts Cheatsheet

Core vocabulary you'll encounter implementing OAuth.

Term Meaning
Client ID / Secret Credentials identifying your app to the provider
Redirect URI Where the provider sends the user back after consent
Authorization code Short-lived code exchanged for an access token
Access token Grants scoped access to the user's data on the provider
Refresh token Used to obtain a new access token without re-authenticating
Scope The specific permissions requested from the user

Using Passport.js for OAuth

Implementing the OAuth flow by hand for every provider is repetitive and error-prone. Passport.js provides a "strategy" per provider (Google, GitHub, Facebook, and many more), handling the redirect, callback, and token exchange steps consistently.

import passport from 'passport';
import { Strategy as GoogleStrategy } from 'passport-google-oauth20';

passport.use(new GoogleStrategy({
  clientID: process.env.GOOGLE_CLIENT_ID,
  clientSecret: process.env.GOOGLE_CLIENT_SECRET,
  callbackURL: '/auth/google/callback',
}, async (accessToken, refreshToken, profile, done) => {
  const user = await findOrCreateUser(profile);
  done(null, user);
}));

app.get('/auth/google', passport.authenticate('google', { scope: ['profile', 'email'] }));
app.get('/auth/google/callback',
  passport.authenticate('google', { failureRedirect: '/login' }),
  (req, res) => res.redirect('/dashboard')
);

Passport calls your verify callback with the provider's profile data once the OAuth exchange completes, letting you find or create a matching user in your own database.

OAuth vs Building Your Own Login

OAuth doesn't replace the authentication concepts covered earlier in this course, sessions or JWTs are still typically issued by your own server after a successful OAuth login, OAuth simply replaces the credential-collection step with a trusted third party.

Common Mistakes

  • Trying to collect the user's third-party password directly instead of redirecting them to the provider.
  • Hardcoding OAuth client secrets in source code instead of environment variables.
  • Requesting broader scopes than your app actually needs, unnecessarily reducing user trust.
  • Forgetting that OAuth login still needs your own session/JWT issuance step afterward.

Key Takeaways

  • OAuth 2.0 lets users grant limited access without sharing their password with your app.
  • The authorization code flow involves a redirect, a callback with a code, and a server-to-server token exchange.
  • Passport.js provides ready-made strategies for common OAuth providers.
  • OAuth handles third-party identity verification; your app still issues its own session or JWT afterward.

Pro Tip

Request the narrowest OAuth scopes your app actually needs (often just profile and email). Users are understandably wary of apps requesting broad account access, and minimal scopes also reduce your own liability if a token is ever compromised.