Zum Hauptinhalt springen
tsecurity.de LIVE
Echtzeit-Radar & Feeds
Alle RSS Feeds
👥 Community & Social
Sichere ProgrammierungNew features and improvements in Copilot for JetBrains(23.09.2026 um 02:34 Uhr)
Sichere Programmierung5 Things I Learned From Bad AI Video Generations(23.09.2026 um 02:44 Uhr)
Sichere ProgrammierungNew features and improvements in Copilot for JetBrains(23.09.2026 um 02:34 Uhr)
Sichere Programmierung5 Things I Learned From Bad AI Video Generations(23.09.2026 um 02:44 Uhr)
Intelligence View
⚡ tsecurity.de Intelligence

How I Handle JWT Authentication in Express.js (Without the Headaches)

Authentication used to stress me out. Not because it's conceptually hard, but because every tutorial I found either oversimplified it to the point of being useless, or made it so complicated I needed a PhD to understand what was…

0
↗ Quelle (dev.to)
Reagiere als Erste:r — dein Feedback zählt!

Authentication used to stress me out.



Not because it's conceptually hard, but because every tutorial I found either oversimplified it to the point of being useless, or made it so complicated I needed a PhD to understand what was happening.



After building several projects and breaking authentication in creative ways, I finally figured out a setup that actually works and doesn't make me want to throw my laptop out the window.



suprised in a good way



Here's how I do it, explained like I'm talking to a friend over coffee, not writing a textbook.






What We're Working With




  • Node.js & Express - The backend


  • MongoDB & Mongoose - Where user data lives


  • bcryptjs - Makes passwords unreadable (important!)


  • jsonwebtoken - Creates those tokens everyone talks about


  • cookie-parser - Handles cookies properly


  • dotenv - Keeps secrets actually secret




Nothing fancy. Nothing you can't install in 30 seconds.






Step 1: Letting People Sign Up



When someone registers, we need to save their info. But we can't just store their password as-is. That's like leaving your house key under the doormat with a sign that says "KEY HERE."




const bcrypt = require('bcryptjs');
const User = require('../models/User');

app.post('/api/register', async (req, res) => {
const { username, email, password } = req.body;

// Turn the password into scrambled nonsense
const hashedPassword = await bcrypt.hash(password, 10);

const user = new User({ username, email, password: hashedPassword });

try {
await user.save();
res.status(201).json({ message: 'User created successfully' });
} catch (err) {
res.status(400).json({ error: 'User already exists or invalid input' });
}
});






What's happening: We take their password and scramble it (that's the hashing part). Even if someone breaks into your database, they just see gibberish instead of actual passwords.




The hacker after breaking into your database:




hacker after breaking into database reaction






Step 2: Logging In and Getting Tokens



This is where it gets interesting. When someone logs in, we give them TWO tokens:




  • Access token - Short-lived (15 minutes). Like a temporary pass to get into places.


  • Refresh token - Lasts longer (5 days). Used to get new access tokens without logging in again.




Why two? Security. If someone steals your access token, it expires quickly. The refresh token stays safe in a cookie.




const jwt = require('jsonwebtoken');

const generateAccessToken = (payload) => {
return jwt.sign(payload, process.env.JWT_SECRET, {expiresIn: '15m'})
}

app.post('/api/login', async (req, res) => {
const { email, password } = req.body;

// Find the user
const user = await User.findOne({ email });
if (!user) return res.status(401).json({ error: 'Invalid credentials' });

// Check if password matches
const isMatch = await bcrypt.compare(password, user.password);
if (!isMatch) return res.status(401).json({ error: 'Invalid credentials' });

// Package up user info
const payload = {
id: user._id,
username: user.username,
email: user.email
}

// Create both tokens
const refreshToken = jwt.sign(
payload,
process.env.JWT_REFRESH_SECRET,
{ expiresIn: '5d' }
);

const accessToken = generateAccessToken(payload);

// Send refresh token as a secure cookie
res.cookie("refreshToken", refreshToken, {
secure: true,
httpOnly: true,
maxAge: 1000 * 60 * 60 * 24 * 7 // 7 days
})

res.status(200).json({ accessToken });
});






What's happening: We check if the user exists, verify their password, then create two tokens. The refresh token goes in a special cookie that JavaScript can't touch (that's the httpOnly part). The access token goes in the response.






Step 3: Getting a New Access Token



After 15 minutes, your access token expires. Instead of making users log in again, we use the refresh token to get a new one.



First, set up cookie parsing in your main file:




const cookieParser = require("cookie-parser");
app.use(cookieParser());






Then create the refresh endpoint:




app.post('/token/refresh', (req, res) => {
// Get the refresh token from the cookie
const refreshToken = req.cookies.refreshToken;
if (!refreshToken) return res.status(401).json({ error: 'No token' });

// Verify it's legit
const verifiedToken = jwt.verify(refreshToken, process.env.JWT_REFRESH_SECRET);
if (!verifiedToken) return res.status(403).json({ error: 'Invalid token' });

// Create a new access token
const {id, username, email} = verifiedToken;
const accessToken = generateAccessToken({id, username, email});

res.status(200).json({ accessToken });
});






What's happening: We grab the refresh token from the cookie, check if it's valid, and if it is, we create a fresh access token. Simple.



inspecting refresh access token meme






Step 4: Protecting Routes



Now we need to make sure only logged-in users can access certain routes. That's what middleware is for.




const authMiddleware = (req, res, next) => {
const authHeader = req.headers.authorization;
if (!authHeader) return res.status(401).json({ error: 'No token provided' });

// Token comes as "Bearer actualtoken", so we split it
const token = authHeader.split(' ')[1];

try {
const decoded = jwt.verify(token, process.env.JWT_SECRET);
req.user = decoded; // Now we know who's making the request
next();
} catch (err) {
res.status(403).json({ error: 'Invalid or expired token' });
}
};

// Use it on any route you want to protect
app.get('/api/profile', authMiddleware, async (req, res) => {
const user = await User.findById(req.user.id).select('-password');
res.json(user);
});






What's happening: The middleware checks if there's a valid token. If yes, attach the user info to the request and move on. If no, reject them. Think of it as a bouncer checking IDs.






Why This Setup Works



It's stateless. No need to store sessions on the server. Everything lives in the tokens.



It scales. Works whether you have 10 users or 10,000.



It's secure enough. Passwords are hashed, tokens expire, and the refresh token is protected.



It's not overwhelming. You can understand what each piece does without a computer science degree.



simple but honest work






What I'd Add Next



Right now, this handles basic authentication. But for bigger projects, you might want:




  • Role-based access - Admins can do more than regular users


  • Token blacklisting - Invalidate tokens when users log out


  • Rate limiting - Stop people from spamming your login endpoint




But for most projects? This setup is solid.






The Real Talk



Authentication doesn't have to be scary or complicated. Yes, there are edge cases. Yes, there are more secure ways to do things. But this approach has worked for my projects, and it's simple enough that I can set it up in an hour without pulling my hair out.



If you're just starting with backend auth or you've been putting it off because it seems overwhelming, start here. Get it working, understand what each part does, then optimize later.



Perfect is the enemy of shipped.



Got questions? Different approach? Let me know in the comments. Always happy to learn better ways to do this.



Goodbye reaction meme



Originally published on My Blog

Ähnliche Beiträge
🔍 Verwandte News

Auch interessante Nachrichten How I Handle JWT Authentication in Express.js (Without the Headaches)

Thematisch verwandte Begriffe: Handle, Authentication, Expressjs, Without · 6 Treffer

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Zum Aktualisieren ziehen
ZERO-DAY CVE-2026-17636 | IBM Financial Transaction Manager (FTM) for RedHat OpenShift could allow…
Advisory →
TTS Reader • tsecurity.de Voice
tsecurity.de Icon
tsecurity.de App
Offline-Lesen, Eilmeldungen & 0ms Ladezeit

Installiere tsecurity.de direkt auf deinen Home-Bildschirm für das ultimative Vollbild-Magazinerlebnis ohne Browser-Leisten.

Nächster Beitrag
Themen-Radar & Intelligence Matrix
Echtzeit-Taxonomie nach Angriffsvektoren & Plattformen

tsecurity.de Live Threat Radar

🔴 LIVE RADAR
MONITORING
AKTIV
CVE-DATENBANK
LIVE
🔍
Community Radar & Live Chat
Sentinel Bot online • Live-Stream
Dein Cluster: Security Explorer
Match:
lädt…
Verbindung zum Community-Stream wird aufgebaut...
Bearbeitungsmodus — Senden überschreibt deine Nachricht
Community-Puls — was gerade passiert
lädt…
Aktivitäten deiner Analysten
lädt…
Neues Thema oder Eilmeldung einreichen

Reiche interessante Links, Zero-Days oder Debatten ein. Die Community entscheidet per Upvote über die Veröffentlichung.

Heiß diskutierte Einreichungen
🔖 Gespeicherte Artikel
📂 Keine gespeicherten Artikel vorhanden.
Zurück Ziehen Vor
Links: vorheriger Artikel Rechts: nächster Artikel unten: schließen
News NIS-2 Frühwarnung Tier-1 Intel ⏱️ 3 Min vor 10 Min
Artikeldaten werden geladen...

Zurück: vorheriger Vor: nächster
↗ Original-Quelle
Social Reaktionen Deine Reaktion zählt
Einstufung & Relevanz-Poll 0 Stimmen
In sozialen Netzwerken teilen 1-Klick