When building secure Express.js applications, you’ll likely face a key architectural choice:
Should you use cookie-based authentication or bearer tokens like JWTs?
Each method has unique advantages depending on your frontend, deployment, and security requirements. In this post, we’ll break it down clearly and practically.
Why It Matters
- Defines how your app handles sessions and security
- Impacts frontend integration, especially for SPAs
- Affects protection against attacks like CSRF and XSS
- Determines whether tokens are sent automatically or manually
Option 1: Cookie-Based Authentication
How It Works
- Server sets a cookie containing a session ID or JWT
- Browser stores it and automatically sends it with every request — if configured correctly
res.cookie('token', jwtToken, {
httpOnly: true,
secure: true,
sameSite: 'Strict'
});
To access it:
import cookieParser from 'cookie-parser';
app.use(cookieParser());
app.get('/dashboard', (req, res) => {
const token = req.cookies.token;
});
When Are Cookies Sent Automatically?
Cookies are included in requests when:
- The origin matches the cookie's domain
-
sameSite
allows the request (Lax
,Strict
, orNone
) -
credentials: 'include'
is used in fetch/axios for cross-origin requests - Connection is over HTTPS if
secure: true
fetch('http://api.example.com/user', {
credentials: 'include'
});
Option 2: Bearer Token Authentication (JWT)
How It Works
- Client stores token manually (e.g., in localStorage)
- Token is explicitly added to the
Authorization
header
fetch('/api/protected', {
headers: {
Authorization: `Bearer ${token}`
}
});
On the backend:
const authHeader = req.headers.authorization;
const token = authHeader?.split(' ')[1];
Cookie vs Bearer Token: Quick Comparison
Feature | Cookie Auth | Bearer Token (JWT) |
---|---|---|
Auto-sent by browser | Yes | No |
Ideal for | Web apps / SSR / same-origin | APIs / mobile / cross-origin |
Requires CSRF tokens | Yes (if not using SameSite ) |
No |
Vulnerable to XSS | No (if HttpOnly ) |
Yes (if stored in JS) |
Cross-origin support | Needs config | Easier |
When to Use Which
Use Cookie Auth if:
- You’re building a browser-first app (SSR or same-origin SPA)
- You want session management without manually handling tokens in JS
- You plan to use
HttpOnly
cookies for security
Use Bearer Token if:
- You need to support mobile apps, external clients, or third-party integrations
- You're building a fully decoupled frontend/backend
- You prefer handling tokens explicitly in headers
Real-World Example: Cross-Origin Cookie Setup
Backend:
res.cookie('token', jwtToken, {
httpOnly: true,
secure: true,
sameSite: 'None'
});
Frontend:
fetch('http://api.example.com/data', {
credentials: 'include'
});
Final Thoughts
There’s no one-size-fits-all.
Cookies excel at browser-based workflows, especially when using HttpOnly
and SameSite
.
Bearer tokens give you flexibility, especially across different platforms or APIs.
Both are secure when implemented correctly — just make sure you understand the browser behavior, attack vectors, and configuration nuances.
Top comments (0)