โœˆ ETHIOCODE SOFTSELECT
LESSON 17 ยท SECURITY

JWT & bcrypt Authentication ๐Ÿ”

Login แŠ• แˆ™แˆ‰ แˆˆแˆ™แˆ‰ แ‹ฐแˆ…แŠ•แАแ‰ฑ แ‹จแ‰ฐแŒ แ‰ แ‰€ แˆแŠ•! Password Hashing + Token Authentication ๐Ÿ”ฅ
Build secure login systems โ€” hash passwords with bcrypt, protect routes with JWT tokens!

A
Created by @AppMinds_ET
01 ๐Ÿค”
Authentication แˆแŠ•แ‹ตแŠ• แАแ‹?// Who Are You?

Authentication (Auth) = "แ‹ญแˆ… แˆฐแ‹ แˆ›แŠ• แАแ‹? Login แˆ†แŠ—แˆแŠ•?" โ€” แˆˆแ‹šแˆ… 2 แ‹‹แŠ“ tools แŠฅแŠ•แŒ แ‰€แˆ›แˆˆแŠ•:
bcrypt โ€” Password แŠ• แ‹ฐแˆ…แŠ•แАแ‰ฑ แ‰ฃแˆˆ แˆ˜แˆแŠฉ hash แ‹ซแ‹ฐแˆญแŒ‹แˆ
JWT โ€” Login แŠจแˆ†แА แ‰ แŠ‹แˆ‹ token แ‹ญแˆฐแŒฃแˆ โ€” แ‰€แŒฃแ‹ญ requests token แ‹ซแˆตแˆแˆแŒ‹แ‰ธแ‹‹แˆ!
Authentication = verifying WHO the user is. bcrypt protects passwords. JWT proves the user is logged in.

๐Ÿ’ก แˆแˆณแˆŒ แ‰ฐแŒ แ‰…แˆž แˆˆแˆ˜แˆจแ‹ณแ‰ต โ€” Hotel Analogy
bcrypt
๐Ÿ”‘ Passport แˆ›แˆจแŒ‹แŒˆแŒซ
Password แŠ• แ‰€แŒฅแ‰ณ แŠ แŠ“แˆตแ‰€แˆแŒฅ โ€” hash แˆ†แŠ– แ‹ญแ‰€แˆ˜แŒฃแˆ! แˆŒแˆ‹ แˆฐแ‹ แ‰ขแˆฐแˆญแ‰… แŠ แ‹ซแАแ‰ แ‹แˆ!
โ†’
JWT Token
๐ŸŽซ Hotel Room Key Card
Login แŠจแˆ†แА key card แ‹ญแˆฐแŒฃแˆƒแˆ โ€” แ‰€แŒฃแ‹ญ แˆแˆ‰แˆ rooms แ‹ซ key แ‰ฅแ‰ป แ‹ญแŠจแแ‰ณแ‰ธแ‹‹แˆ!
Register
๐Ÿ“ Hotel Check-in
Password hash แˆ†แŠ– Database แ‹ญแ‰€แˆ˜แŒฃแˆ
โ†’
Login
โœ… Check โ€” JWT แ‹ญแˆฐแŒฃแˆƒแˆ
Password แ‰ตแŠญแŠญแˆ แŠจแˆ†แА JWT token แ‹ญแˆฐแŒฃแˆƒแˆ
02 ๐Ÿ”„
Auth Flow โ€” แˆ™แˆ‰ แˆ‚แ‹ฐแ‰ต// Register โ†’ Login โ†’ Protected

แˆแ‹แŒˆแ‰ฃ แŠจ Protected Route แ‹ตแˆจแˆต โ€” แˆ™แˆ‰ แˆ‚แ‹ฐแ‰ต:

STEP 01
๐Ÿ“
Register
Password hash แˆ†แŠ– DB แ‹ญแ‰€แˆ˜แŒฃแˆ
โ†’
STEP 02
๐Ÿ”
Login
bcrypt compare โ†’ JWT token แ‹ญแˆฐแŒฃแˆƒแˆ
โ†’
STEP 03
๐ŸŽซ
Store Token
localStorage แ‹ˆแ‹ญแˆ cookie
โ†’
STEP 04
๐Ÿ“ก
API Request
Header: Bearer TOKEN
โ†’
STEP 05
โœ…
Verify
Server token แ‹ซแˆจแŒ‹แŒแŒฃแˆ โ†’ Response
03 ๐Ÿ”’
bcrypt โ€” Password Hashing// Never Store Plain Text!

Password แŠ• แ‰€แŒฅแ‰ณ Database แŠ แ‰ตแ‰€แˆแŒฅ! แˆŒแˆ‹ แˆฐแ‹ DB แ‰ขแˆฐแˆญแ‰… แˆแˆ‰แˆ passwords แ‹ซแ‹ซแ‰ธแ‹‹แˆ! bcrypt password แŠ• hash (แˆŠแАแ‰ แ‰ฅ แ‹จแˆ›แ‹ญแ‰ปแˆ string) แ‹ซแ‹ฐแˆญแŒˆแ‹‹แˆ!
NEVER store plain text passwords! bcrypt hashes them into an unreadable string. Even bcrypt can't reverse it โ€” can only verify!

โŒ แ‰€แŒฅแ‰ณ DB แ‹แˆตแŒฅ
"password123"
โ†’
โœ… Hash แˆ†แŠ– DB แ‹แˆตแŒฅ
"$2b$10$N9qo8uLOick...xWyF8"
auth.js โ€” bcrypt Register & Login
const bcrypt   = require('bcryptjs');   // npm install bcryptjs
const User     = require('../models/User');

// โ”€โ”€ REGISTER โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
router.post('/register', async (req, res) => {
  const { name, email, password } = req.body;

  // 1. Email แŠ แˆตแ‰€แ‹ตแˆž แŠ แˆˆ?
  const exists = await User.findOne({ email });
  if (exists) return res.status(400).json({ error: 'Email in use' });

  // 2. Password hash แ‹ซแ‹ตแˆญแŒ (10 = salt rounds)
  const hashed = await bcrypt.hash(password, 10);

  // 3. Hash แˆ†แА แ‰ฅแ‰ป DB แ‹แˆตแŒฅ แ‰€แˆแŒฅ โ€” แ‰€แŒฅแ‰ณ แŠ แ‹ญแ‹ฐแˆˆแˆ!
  const user = await User.create({ name, email, password: hashed });

  res.status(201).json({ success: true, message: 'Registered!' });
});

// โ”€โ”€ LOGIN โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
router.post('/login', async (req, res) => {
  const { email, password } = req.body;

  // 1. User แˆแˆแŒ
  const user = await User.findOne({ email });
  if (!user) return res.status(400).json({ error: 'Invalid credentials' });

  // 2. Password แ‹ซแˆจแŒ‹แŒแŒฅ (plain vs hashed)
  const match = await bcrypt.compare(password, user.password);
  if (!match) return res.status(400).json({ error: 'Invalid credentials' });

  // 3. JWT token แˆตแŒฅ โ† แ‰€แŒฅแˆŽ แŠฅแŠ“แ‹ซแˆˆแŠ•!
  const token = jwt.sign({ id: user._id }, process.env.JWT_SECRET, { expiresIn: '7d' });

  res.json({ success: true, token });
});
04 ๐ŸŽซ
JWT โ€” JSON Web Token// Stateless Auth

JWT = Login แˆตแŠฌแ‰ณแˆ› แˆฒแˆ†แŠ• server token แ‹ญแˆฐแŒฃแˆ โ€” แ‰€แŒฃแ‹ญ requests แˆแˆ‰ แ‹ซ token แ‹ซแˆตแˆแˆแŒ‹แ‰ธแ‹‹แˆ! Server session แŠ แ‹ซแˆตแ‰€แˆแŒฅแˆ โ€” token แˆซแˆฑ แˆแˆ‰แŠ• แ‹ญแ‹Ÿแˆ!
JWT is a self-contained token. The server doesn't store sessions โ€” it just verifies the token signature on every request!

๐Ÿ” JWT Structure โ€” 3 แŠญแแˆŽแ‰ฝ dot แˆ†แŠ– แ‹ญแ‹‹แˆƒแ‹ณแˆ‰:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9 . eyJpZCI6IjY0YTNmIiwibmFtZSI6IkFiZWwiLCJpYXQiOjE2OTk5fQ . SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
HeaderAlgorithm type
PayloadUser data (id, name...)
SignatureVerify yadergal
middleware/protect.js โ€” JWT Verify Middleware
const jwt = require('jsonwebtoken');  // npm install jsonwebtoken

// โ”€โ”€ Middleware โ€” แˆแˆ‰แˆ protected routes แ‹ญแŒ แ‰€แˆ™แ‰ณแˆ โ”€โ”€
function protect(req, res, next) {
  // 1. Header แ‹แˆตแŒฅ token แŠ แˆˆ?
  const authHeader = req.headers.authorization;
  if (!authHeader || !authHeader.startsWith('Bearer ')) {
    return res.status(401).json({ error: 'No token โ€” Login แ‹ซแˆตแˆแˆแŒ‹แˆ!' });
  }

  // 2. Token แŠ• แˆˆแ‹ญ (Bearer xxxxx โ†’ xxxxx)
  const token = authHeader.split(' ')[1];

  try {
    // 3. Token แŠ• แ‹ซแˆจแŒ‹แŒแŒฅ
    const decoded = jwt.verify(token, process.env.JWT_SECRET);
    req.user = decoded; // user info แ‹ˆแ‹ฐ request แŒจแˆแˆญ
    next();             // แ‰€แŒฅแˆŽ แ‹ซแˆˆแ‹ route แ‹ญแˆ‚แ‹ต
  } catch (err) {
    res.status(401).json({ error: 'Invalid token!' });
  }
}

// โ”€โ”€ Protected routes โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
router.get('/profile', protect, (req, res) => {
  res.json({ user: req.user }); // token แŠซแˆˆ แ‰ฅแ‰ป แ‹ญแˆฐแŒฃแˆ!
});

router.get('/dashboard', protect, (req, res) => {
  res.json({ message: 'แˆฐแˆ‹แˆ! Dashboard แ‰ฐแŠจแˆแ‰ฐ!' });
});

๐Ÿ›ก๏ธ Route Protection Levels:

GET /api/lessons ๐ŸŒ Public
GET /api/profile ๐Ÿ” Login แ‹ซแˆตแˆแˆแŒ‹แˆ
POST /api/posts ๐Ÿ” Login แ‹ซแˆตแˆแˆแŒ‹แˆ
PUT /api/admin/users ๐Ÿ‘‘ Admin Only
DELETE /api/admin/posts/:id ๐Ÿ‘‘ Admin Only
05 ๐ŸŽฎ
Live Auth Demo// Register ยท Login ยท Protected

แˆ™แˆ‰ Authentication system แˆžแŠญแˆญ! Register โ†’ Password hash แ‹ญแˆ†แŠ“แˆ | Login โ†’ JWT token แ‹ญแˆฐแŒฅแˆƒแˆ | Protected Route โ†’ Token แŠซแˆŒ แ‹ญแŠจแˆแŠญแˆ‹แˆ!
Full auth flow simulation โ€” register, login, and test protected routes with and without a token!

๐Ÿ” Auth System
Not logged in
๐Ÿ“ Register
๐Ÿ”‘ Login
๐Ÿ›ก๏ธ Protected Route
๐Ÿ‘ค แˆตแˆ / Full Name
โœ‰๏ธ Email
๐Ÿ”’ Password
Password แŒปแ...
โœ‰๏ธ Email
๐Ÿ”’ Password
06 ๐Ÿ“Œ
แ‹‹แŠ“ แ‹‹แŠ“ แАแŒฅแ‰ฆแ‰ฝ// Key Takeaways
1
๐Ÿ”’ bcrypt โ€” Password แ‰€แŒฅแ‰ณ แŠ แ‰ตแ‰€แˆแŒฅ!

bcrypt.hash(password, 10) โ€” 10 salt rounds = แŠƒแ‹ญแˆˆแŠ› hash! bcrypt.compare(plain, hash) โ€” verify แˆˆแˆ›แ‹ตแˆจแŒ!
Never store plain passwords. Hash with 10+ salt rounds. Use bcrypt.compare() to verify on login.

2
๐ŸŽซ JWT โ€” Token Based Auth

jwt.sign({'{'}id{'}'},secret,{'{'}expiresIn:'7d'{'}'}) โ†’ token แ‹ญแˆฐแŒฃแˆƒแˆ! jwt.verify(token,secret) โ†’ แ‹ซแˆจแŒ‹แŒแŒฃแˆƒแˆ!
Sign a token on login. Verify it on every protected request. Set expiration (7d, 1h, etc).

3
๐Ÿ›ก๏ธ Middleware โ€” Routes แˆˆแˆ›แˆตแŒ แ‰ แ‰…

function protect(req,res,next) โ€” Header แ‹แˆตแŒฅ token แ‹ซแˆจแŒ‹แŒแŒฃแˆแข Protected routes แˆแˆ‰ แ‹ญแŒ แ‰€แˆ™แ‰ณแˆ!
Middleware checks for valid JWT before allowing access to protected routes.

4
๐Ÿ”‘ Authorization Header

Client: Authorization: Bearer <token> โ€” แˆแˆ‰แˆ protected request แ‹ญแˆ…แŠ• header แ‹ญแˆแŠซแˆ!
Send token as: Authorization: Bearer eyJhbGci... in every authenticated request header.

5
๐ŸŒ .env โ€” Secrets แˆ›แˆตแ‰€แˆ˜แŒซ

JWT_SECRET=mysecretkey123 โ€” .env file แ‹แˆตแŒฅ แ‰€แˆแŒฅ! GitHub แˆ‹แ‹ญ แˆแŒฝแˆž แŠ แ‰ตแŒซแŠ•!
Store JWT_SECRET in .env file. Add .env to .gitignore โ€” NEVER commit secrets to GitHub!

07 ๐ŸŽฏ
Quiz// แˆแŠ• แ‰ฐแˆ›แˆญแŠ•?
โ“ Password แŠ• Database แŠจแˆ›แˆตแ‰€แˆ˜แŒฅ แ‰ แŠแ‰ต แˆแŠ• แˆ›แ‹ตแˆจแŒ แŠ แˆˆแ‰ฅแŠ•?
What must we do to a password BEFORE storing it in the database?
A แ‰€แŒฅแ‰ณ String แˆ†แŠ– แ‹ซแˆตแ‰€แˆแŒก โ€” "password123"
B Base64 encode แ‹ซแ‹ตแˆญแŒ‰
C bcrypt.hash() แ‰ฐแŒ แ‰…แˆž Hash แ‹ซแ‹ตแˆญแŒ‰ โœ…
D JWT แ‹แˆตแŒฅ แ‹ซแˆตแ‰€แˆแŒก