How to Build a Secure Authentication System with JWT and Refresh Tokens

How to Build a Secure Authentication System with JWT and Refresh Tokens

Introduction

Every app that manages user accounts needs to verify identity.

That’s the role of authentication — ensuring the user is who they claim to be.

Doing this securely is harder than it seems.

Traditional sessions + cookies work well for monolithic web apps, but scale poorly for APIs or mobile clients talking to multiple services.

JSON Web Tokens (JWTs) solve this by providing compact, self-contained, stateless authentication.

JWTs:

  • Can be validated without a server-side session store.
  • Often expire quickly to reduce security risks.

To avoid forcing frequent logins, we add refresh tokens — longer-lived credentials that can quietly fetch new access tokens behind the scenes.

This guide will help you build secure JWT authentication with refresh tokens:

Generate, validate, handle expiry, and defend against common threats.

---

Table of Contents

---

Understanding JWTs

A JWT has 3 parts:

  • Header — token type & signing algorithm
  • Payload — data (claims) like user ID & roles
  • Signature — proves the token hasn’t been altered

They are _Base64URL_ encoded and signed so recipients can verify authenticity without storing state.

Advantages

  • Stateless: Server doesn’t store session data.
  • Efficient for APIs & microservices.

Limitations

  • Cannot easily revoke before expiry.
  • If compromised, attacker can use until expiry.
  • Use short expiry + refresh tokens.

---

Project Setup

We’ll use Node.js + Express, `jsonwebtoken` for JWT handling, and `dotenv` for secrets.

Initialize project:

npm init -y
npm install express jsonwebtoken dotenv

Create `.env` for secrets.

---

JWT Authentication Implementation

Steps:

  • Validate credentials (login)
  • Issue access token — short-lived, used on every request
  • Issue refresh token — long-lived, used only to get new access tokens

Example `/login` endpoint:

const jwt = require('jsonwebtoken');

app.post('/login', (req, res) => {
  const { username, password } = req.body;
  // Validate credentials...

  const accessToken = jwt.sign({ username }, process.env.ACCESS_SECRET, { expiresIn: '15m' });
  const refreshToken = jwt.sign({ username }, process.env.REFRESH_SECRET, { expiresIn: '7d' });

  // Store refreshToken securely (DB)
  res.json({ accessToken, refreshToken });
});

---

Verifying JWTs & Protecting Routes

Create middleware to check tokens:

function authenticateToken(req, res, next) {
  const authHeader = req.headers['authorization'];
  const token = authHeader && authHeader.split(' ')[1];

  if (!token) return res.sendStatus(401);

  jwt.verify(token, process.env.ACCESS_SECRET, (err, user) => {
    if (err) return res.sendStatus(403);
    req.user = user;
    next();
  });
}

Apply to protected routes.

---

Refresh Tokens & Rotation

When access token expires, client uses refresh token to get a new one:

app.post('/token', (req, res) => {
  const { refreshToken } = req.body;
  if (!refreshToken) return res.sendStatus(401);

  jwt.verify(refreshToken, process.env.REFRESH_SECRET, (err, user) => {
    if (err) return res.sendStatus(403);

    const newAccessToken = jwt.sign({ username: user.username }, process.env.ACCESS_SECRET, { expiresIn: '15m' });
    res.json({ accessToken: newAccessToken });
  });
});

Rotation: Issue a new refresh token on use, invalidate old one.

---

Security Best Practices

  • Separate secrets for access & refresh tokens
  • Short access TTL (e.g. 15m), longer refresh TTL (e.g. 7d)
  • Store refresh tokens hashed in DB
  • Use `httpOnly`, `secure`, `sameSite` cookies in production
  • Always serve over HTTPS
  • Rotate refresh tokens every use
  • Log IP & user-agent for session awareness
  • Implement revocation & rate-limit refresh endpoint

---

Conclusion

JWT + refresh tokens = scalable, stateless authentication.

Key points:

  • Keep secrets private
  • Protect all sensitive routes with middleware
  • Use short-lived access tokens
  • Rotate & store refresh tokens securely

These principles apply beyond user auth — to any system needing secure, token-based access.

For multi-platform APIs or AI-driven content tools, secure token handling protects both users & data.

➡ Example: AiToEarn官网 — open-source AI content monetization platform for publishing across Douyin, Kwai, WeChat, Bilibili, Rednote, Facebook, Instagram, LinkedIn, Threads, YouTube, Pinterest, and X — relies on similar secure authentication flows for safe cross-platform content delivery.

Read more

Translate the following blog post title into English, concise and natural. Return plain text only without quotes. 哈佛大学 R 编程课程介绍

Harvard CS50: Introduction to Programming with R Harvard University offers exceptional beginner-friendly computer science courses. We’re excited to announce the release of Harvard CS50’s Introduction to Programming in R, a powerful language widely used for statistical computing, data science, and graphics. This course was developed by Carter Zenke.