Node.js JWT Authentication with MySQL — Beginner Tutorial

Node.js JWT Authentication with MySQL — Beginner Tutorial

๐Ÿ“Œ Introduction

In this tutorial, you’ll learn how to add authentication to your Node.js application using JWT (JSON Web Token).

You will build secure API routes that require users to log in before accessing protected resources.

By the end of this guide, you’ll have a complete Register → Login → Protected Route → Logout authentication system using Node.js, Express, MySQL, and JWT.

✅ Prerequisites

Before starting, you should already know:

  • Basic Express API concepts

  • User registration with encrypted passwords

  • User login with JWT token generation

  • How middleware works in Express

You must have installed:

  • Node.js & npm

  • MySQL (running locally)

  • Postman (for API testing)

๐Ÿ—„️ Step 1 — Set Up the Database

Open your MySQL terminal and run:

CREATE DATABASE auth_demo;
USE auth_demo;

CREATE TABLE users (
  id INT AUTO_INCREMENT PRIMARY KEY,
  name VARCHAR(100),
  email VARCHAR(100) UNIQUE,
  password VARCHAR(255)
);

This table stores registered users with hashed passwords.

๐Ÿ“ Step 2 — Set Up the Project

Create a new project folder:

mkdir node-jwt-auth
cd node-jwt-auth

Initialize the project and install dependencies:

npm init -y
npm install express mysql2 bcryptjs jsonwebtoken cors

๐Ÿงฉ Step 3 — Create app.js and Base Setup

const express = require('express');
const mysql = require('mysql2');
const bcrypt = require('bcryptjs');
const jwt = require('jsonwebtoken');
const cors = require('cors');

const app = express();
const PORT = 3000;

app.use(cors());
app.use(express.json());

MySQL Connection

const db = mysql.createConnection({
  host: 'localhost',
  user: 'root',
  password: '',
  database: 'auth_demo'
});

db.connect(err => {
  if (err) throw err;
  console.log('✅ MySQL Connected!');
});

JWT Secret Key

const SECRET_KEY = 'mysecretkey';

๐Ÿ“ Step 4 — Register User (POST)

Route: /api/register

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

  if (!name || !email || !password)
    return res.status(400).json({ message: 'All fields required' });

  db.query('SELECT * FROM users WHERE email = ?', [email], async (err, results) => {
    if (results.length > 0)
      return res.status(400).json({ message: 'Email already registered' });

    const hashedPassword = await bcrypt.hash(password, 10);

    const sql = 'INSERT INTO users (name, email, password) VALUES (?, ?, ?)';
    db.query(sql, [name, email, hashedPassword], err => {
      if (err) throw err;
      res.json({ message: 'User registered successfully!' });
    });
  });
});

๐Ÿงช Test with Postman

POST http://localhost:3000/api/register
{
  "name": "Souy",
  "email": "souy@example.com",
  "password": "123456"
}

๐Ÿ” Step 5 — Login User (POST)

Route: /api/login

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

  if (!email || !password)
    return res.status(400).json({ message: 'Email and password required' });

  db.query('SELECT * FROM users WHERE email = ?', [email], async (err, results) => {
    if (results.length === 0)
      return res.status(401).json({ message: 'Invalid email or password' });

    const user = results[0];
    const validPassword = await bcrypt.compare(password, user.password);

    if (!validPassword)
      return res.status(401).json({ message: 'Invalid email or password' });

    const token = jwt.sign(
      { id: user.id, email: user.email },
      SECRET_KEY,
      { expiresIn: '1h' }
    );

    res.json({ message: 'Login successful', token });
  });
});

๐Ÿ›ก️ Step 6 — JWT Middleware (Protect Routes)

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

  if (!token)
    return res.status(401).json({ message: 'Access denied: No token provided' });

  jwt.verify(token, SECRET_KEY, (err, decoded) => {
    if (err)
      return res.status(403).json({ message: 'Invalid or expired token' });

    req.user = decoded;
    next();
  });
}

๐Ÿ‘ค Step 7 — Protected Route (GET)

Route: /api/profile

app.get('/api/profile', verifyToken, (req, res) => {
  const userId = req.user.id;

  db.query(
    'SELECT id, name, email FROM users WHERE id = ?',
    [userId],
    (err, results) => {
      if (err) throw err;
      res.json({ user: results[0] });
    }
  );
});

๐Ÿงช Test in Postman

  • Method: GET

  • URL: http://localhost:3000/api/profile

  • Header:

Authorization: Bearer YOUR_JWT_TOKEN

๐Ÿ”“ Step 8 — Logout User (JWT)

JWT authentication is stateless, so logout is handled on the client side.

How Logout Works

  • Remove JWT token from browser or app

  • Without the token, protected routes are inaccessible

Example (Frontend)

localStorage.removeItem('token');

Optional Logout API

app.post('/api/logout', (req, res) => {
  res.json({ message: 'Logout successful. Please remove token on client.' });
});

๐Ÿš€ Step 9 — Start the Server

app.listen(PORT, () => {
  console.log(`๐Ÿš€ Server running at http://localhost:${PORT}`);
});

Run the app:

node app.js

๐Ÿง  Summary

In this tutorial, you learned how to:

  • Register users with hashed passwords

  • Authenticate users using JWT

  • Protect routes using middleware

  • Implement logout in JWT authentication

  • Store and manage users in MySQL

  • Build a secure Node.js authentication system

✅ This setup is production-ready for small projects and perfect for beginners.

Souy Soeng

Souy Soeng

Hi there ๐Ÿ‘‹, I’m Soeng Souy (StarCode Kh)
-------------------------------------------
๐ŸŒฑ I’m currently creating a sample Laravel and React Vue Livewire
๐Ÿ‘ฏ I’m looking to collaborate on open-source PHP & JavaScript projects
๐Ÿ’ฌ Ask me about Laravel, MySQL, or Flutter
⚡ Fun fact: I love turning ☕️ into code!

Post a Comment

CAN FEEDBACK
close