Skip to main content

Express.js Authentication Methods

Authentication is one of those topics that makes a lot of beginners freeze up. It sounds serious — like something only security experts should touch. 

But once you strip away the fancy vocabulary, it's really just about answering one simple question: "How does my app know who this person is?"

Let's walk through it together, nice and slow.

First, Let's Clear Up Two Confusing Words

Before touching any code, there are two terms people constantly mix up: authentication and authorization. They sound similar, but they mean very different things.

  • Authentication = Proving who you are. Like showing your ID at the airport.
  • Authorization = What you're allowed to do once you're recognized. Like your ID getting you past security, but only your boarding pass lets you onto a specific plane.

So authentication gets you in the door. Authorization decides which rooms you're allowed to walk into once you're inside.

Why Should You Even Bother With Authentication?

It's not just about locking hackers out (though that's a big part of it). Good authentication also:

  • Remembers who a user is, so they don't have to log in every five minutes
  • Keeps personal data private and safe
  • Builds trust — nobody wants to use an app that feels unsafe
  • Protects your app from people pretending to be someone they're not

With how common cyberattacks have become, skipping authentication is basically leaving your front door wide open.

The Main Authentication Methods in Express.js

There's no single "correct" way to handle authentication. Different apps need different levels of security and convenience. Here are the four most common approaches you'll run into.

1. Basic Authentication (The Simplest, Least Secure Option)

This is the most old-school method. Every time someone makes a request, they send their username and password along with it, tucked inside the request headers.

app.use((req, res, next) => {
  const auth = {login: 'admin', password: 'secret'};
  
  const b64auth = (req.headers.authorization || '').split(' ')[1] || '';
  const [login, password] = Buffer.from(b64auth, 'base64').toString().split(':');
  
  if (login && password && login === auth.login && password === auth.password) {
    return next();
  }

  res.set('WWW-Authenticate', 'Basic realm="401"');
  res.status(401).send('Authentication required.');
});

What's happening here:

  • const auth = {...} — This is just a hardcoded example username and password to compare against. In a real app, you'd be checking against a database instead.
  • Grabbing the header — When someone logs in with Basic Authentication, their browser sends their credentials encoded (not encrypted!) inside the authorization header. This line pulls that value out.
  • Decoding it — The credentials arrive scrambled in a format called Base64. This line unscrambles it back into a readable login:password pair.
  • Checking the match — If the submitted login and password match what's expected, the request is allowed to continue with next().
  • If it doesn't match — The server responds with a 401 status, which is the standard "you're not authenticated" error code, and asks the browser to prompt for credentials again.

The catch: Since the credentials are just encoded, not encrypted, this method is only safe when paired with HTTPS. Without it, anyone snooping on the connection could easily decode the credentials. Think of it as writing your password on a postcard instead of sealing it in an envelope — it's readable if someone intercepts it along the way.

2. Token-Based Authentication (The Modern Favorite)

Instead of sending your username and password over and over with every request, you log in once, and the server hands you a token — kind of like a wristband at a concert. From then on, you just show the wristband instead of proving your identity all over again.

The most popular version of this is JWT (JSON Web Token).

const jwt = require('jsonwebtoken');

// Middleware to check token
const verifyToken = (req, res, next) => {
  const token = req.headers['x-access-token'];
  if (!token) return res.status(403).send('Token is missing.');

  jwt.verify(token, 'your-secure-key', (err, decoded) => {
    if (err) return res.status(500).send('Failed to authenticate token.');
    req.userId = decoded.id;
    next();
  });
};

What's happening here:

  • Importing jsonwebtoken — This is the library that does the heavy lifting of creating and checking tokens.
  • Grabbing the token — Instead of a username and password, the client sends a token in the request headers (x-access-token in this example).
  • No token? Reject it. If there's nothing there, the server responds immediately with a 403, meaning "access forbidden."
  • jwt.verify(...) — This checks whether the token is legit and hasn't been tampered with, using a secret key only your server knows.
  • If it's invalid — The server responds with an error.
  • If it's valid — The decoded information (like the user's ID) gets attached to the request object, so the rest of your app knows exactly who's making the request.

Tokens are popular because they're lightweight, work well across multiple servers, and are great for mobile apps and APIs.

3. OAuth (The "Login With Google/Facebook" Method)

You've definitely used this before, even if you didn't know it by name. OAuth is what happens whenever you click "Sign in with Google" or "Continue with Facebook" instead of creating a brand-new password for every single website.

OAuth lets a third-party service (like Google) vouch for a user's identity, without your app ever seeing or storing their actual password.

Here's the general flow, broken down simply:

  1. Register your app with the OAuth provider (like Google or Facebook), so they know who's asking.
  2. Redirect the user to that provider's login page.
  3. Handle the callback — once the user logs in there, the provider sends them back to your app along with an access token.
  4. Use the token to access whatever information the user allowed you to see (like their name or email).

Because setting this up from scratch is fairly involved, most developers use a library like Passport.js to handle the heavy lifting instead of building it by hand.

4. Session-Based Authentication (The Classic Server-Remembers-You Method)

This method works a little differently. Instead of the client holding onto a token, the server keeps track of who's logged in, and gives the user's browser a small cookie as a reference number to that stored session.

const session = require('express-session');

app.use(session({
  secret: 'your-secret-key',
  resave: false,
  saveUninitialized: true,
  cookie: { secure: true }
}));

app.get('/login', (req, res) => {
  // Store user session info
  req.session.userId = 'exampleUserId';
  res.send('Logged in!');
});

What's happening here:

  • express-session — This is the library that manages sessions for you.
  • app.use(session({...})) — This sets up session handling for your whole app. The secret is used to keep session data secure, and cookie: { secure: true } makes sure the cookie is only sent over HTTPS.
  • req.session.userId = ... — Once a user logs in, you can store whatever info you want about them right on the session object, and Express handles remembering it for you on future requests.

Think of it like getting a wristband at a coat check. You don't carry your coat around all day — you just carry the ticket, and the server (coat check attendant) keeps track of the actual details behind the scenes.

So... Which One Should You Actually Use?

Honestly, it depends on what you're building. Here's a simple way to think about it:

  • Building something small or just learning? Basic or session-based authentication is easy enough to get started with.
  • Building an API or a mobile app? Token-based authentication (JWT) tends to work best since it doesn't rely on cookies or server memory.
  • Want users to log in with existing accounts like Google or GitHub? OAuth is the way to go.
  • Care most about scaling to lots of users across multiple servers? Tokens are usually more flexible than sessions, since sessions require the server to remember each user.

A few extra things worth thinking about:

  • Scalability — If your app might grow big, token-based auth generally scales more easily than sessions.
  • Security needs — OAuth tends to offer stronger security, but it takes more effort to set up properly.
  • User experience — Nobody enjoys re-entering passwords constantly, so smoother methods (like OAuth or tokens) tend to keep users happier.

Popular posts from this blog

How to Check if Someone is Connected to Your Machine in Linux

Picture this: you glance at your system monitor and notice your CPU is humming along even though you're not running anything demanding. Or maybe your internet feels sluggish for no obvious reason. A small, uneasy thought creeps in — is someone else on my machine right now? For Linux users, this isn't something you have to wonder about. Linux ships with a powerful set of built-in tools that let you see exactly who's connected, who's logged in, and what your network is doing at any given moment. You don't need to be a security expert to use them — you just need to know where to look. This guide walks you through the practical, no-nonsense steps to check for unauthorized connections on your Linux system, with real commands you can run right now. Why Monitoring Network Connections Matters Every device on a network — including your own Linux machine — communicates using an IP address. When another device or user connects to your system, that connection shows up as a trac...

How to Set Up a Linux Web Server and Host an HTML Page Easily

Setting up a web server on Linux means spending a fair amount of time in the terminal — Linux leans heavily on the command line rather than clicking through menus, so you'll be typing out instructions more often than not.  If you're new to this, it can feel a little intimidating at first, but the good news is you don't need to become a Linux wizard overnight. A handful of core commands will get you surprisingly far. A few you'll lean on constantly: cd — move between directories ls — see what's in the current directory mkdir — create a new folder nano or vim — edit files right there in the terminal sudo — run something with administrator privileges Get comfortable with these and you'll be able to navigate around, tweak configuration files, and install software without much trouble. You don't need to memorize everything — you just need to be confident enough to follow along with clear instructions, which is exactly what this guide aims to give you....

Linux Network Troubleshooting

If you've spent any time as a sysadmin — or honestly, just as someone who's had to fix their own home network at 11pm — you know that connectivity issues are one of the most common headaches out there. The good news is that a handful of core tools and a methodical approach can take you from "why isn't this working" to a root cause pretty quickly.  This guide walks through the essentials: configuring interfaces, managing routes, and diagnosing problems when things go sideways. Configuring Network Interfaces Your network interfaces are the actual bridge between your machine and the outside world, so getting them configured correctly is step one for any kind of reliable connectivity. Doing It Manually ifconfig is the old-school, tried-and-true tool for this on Unix-like systems. To see everything currently configured, run: ifconfig -a If you need to manually set up a specific interface — assigning an IP, a netmask, and bringing it online — it looks like this: ifconf...