Express JWT va API token

Kirish darsida qurgan sessiya tizimi brauzerda yaxshi ishlaydi. Lekin API’ngizga mobil ilova ulansa, vaziyat o’zgaradi: mobil ilovada cookie mexanizmi brauzerdagidek avtomatik emas. Uch server ishlasa, sessiyani ular orasida bo’lishish uchun qo’shimcha ombor kerak bo’ladi.

Bu darsda boshqa yondashuv — token. Ma’lumot serverda emas, mijozda saqlanadi, lekin uni o’zgartirib bo’lmaydi.

JWT nima

Token uch qismdan iborat, nuqta bilan ajratilgan:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VySWQiOjIsImVtYWlsIjoibm9kaXJhQGV4YW1wbGUuY29tIiwiaWF0IjoxNzg5MjIyNDc0LCJleHAiOjE3ODkyMjYwNzR9.MR0nlbo0VLP01DBXMpzwWi_TX_ss3dplVjw_0Zkf7rY
Qism Nomi Nima bor
1 Header Algoritm nomi
2 Payload Ma’lumot: userId, muddat
3 Signature Imzo — maxfiy kalit bilan hisoblangan

Payload shifrlanmaydi

Birinchi ikki qism oddiy Base64 kodlash — shifrlash emas. Har kim ochib o’qiy oladi:

const jwt = require("jsonwebtoken");

const token = jwt.sign(
  { userId: 2, email: "nodira@example.com" },
  "sinov-kaliti-uzun-va-tasodifiy",
  { expiresIn: "1h" }
);

const parts = token.split(".");

console.log("Header:", Buffer.from(parts[0], "base64url").toString());
console.log("Payload:", Buffer.from(parts[1], "base64url").toString());
node jwt-parts.js
Header: {"alg":"HS256","typ":"JWT"}
Payload: {"userId":2,"email":"nodira@example.com","iat":1789222474,"exp":1789226074}

Maxfiy kalit ishlatilmadi, shunga qaramay ma’lumot o’qildi.

Payload’dagi ikki maydon avtomatik qo’shildi:

Maydon Ma’nosi
iat Issued at — qachon berilgani
exp Expiration — qachon tugashi

Ikkalasi ham Unix vaqti (1970 yildan beri o’tgan sekundlar).

Imzo nimani to’sadi

const jwt = require("jsonwebtoken");

const token = jwt.sign({ userId: 2 }, "sinov-kaliti-uzun-va-tasodifiy", {
  expiresIn: "1h",
});

// To'g'ri kalit bilan
console.log(jwt.verify(token, "sinov-kaliti-uzun-va-tasodifiy"));

// Boshqa kalit bilan
try {
  jwt.verify(token, "boshqa-kalit");
} catch (error) {
  console.log("Xato:", error.name, "-", error.message);
}
node jwt-verify.js
{ userId: 2, iat: 1789222474, exp: 1789226074 }
Xato: JsonWebTokenError - invalid signature

Muddati tugagan tokenda esa boshqa xato turi:

const expired = jwt.sign({ userId: 2 }, "sinov-kaliti-uzun-va-tasodifiy", {
  expiresIn: "-1s",
});

try {
  jwt.verify(expired, "sinov-kaliti-uzun-va-tasodifiy");
} catch (error) {
  console.log("Xato:", error.name, "-", error.message);
}
Xato: TokenExpiredError - jwt expired

Ikki xil xato nomi — ularni ajratib, foydalanuvchiga aniqroq javob berish mumkin.

Token beradigan marshrut

npm install jsonwebtoken

routes/api-auth.js:

const express = require("express");
const jwt = require("jsonwebtoken");
const User = require("../models/user");

const router = express.Router();

const JWT_SECRET = process.env.JWT_SECRET || "sinov-kaliti-uzun-va-tasodifiy";

router.post("/login", async (request, response, next) => {
  try {
    const email =
      typeof request.body.email === "string" ? request.body.email.trim() : "";
    const password =
      typeof request.body.password === "string" ? request.body.password : "";

    const row = User.findByEmail(email);
    const isValid = row
      ? await User.verifyPassword(password, row.password_hash)
      : false;

    if (!isValid) {
      return response.status(401).json({ error: "Email yoki parol noto'g'ri" });
    }

    // Tokenga faqat id solinadi
    const token = jwt.sign({ userId: row.id }, JWT_SECRET, { expiresIn: "1h" });

    response.json({ token: token, expiresIn: 3600 });
  } catch (error) {
    next(error);
  }
});

module.exports = router;

Parol tekshiruvi oldingi darsdagi bilan bir xil — faqat oxiri boshqacha: sessiya ochish o’rniga token beriladi.

Tokenni tekshiruvchi middleware

Mijoz tokenni Authorization sarlavhasida yuboradi:

Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...

middleware/token.js:

// middleware/token.js
const jwt = require("jsonwebtoken");

const JWT_SECRET = process.env.JWT_SECRET || "sinov-kaliti-uzun-va-tasodifiy";

function requireToken(request, response, next) {
  const header = request.get("Authorization") || "";

  if (!header.startsWith("Bearer ")) {
    return response.status(401).json({ error: "Token yuborilmadi" });
  }

  // "Bearer " so'zidan keyingi qism
  const token = header.slice(7);

  try {
    const payload = jwt.verify(token, JWT_SECRET);
    request.userId = payload.userId;
    next();
  } catch (error) {
    if (error.name === "TokenExpiredError") {
      return response.status(401).json({ error: "Token muddati tugagan" });
    }

    return response.status(401).json({ error: "Token yaroqsiz" });
  }
}

module.exports = { requireToken };

request.userId = payload.userId qatori — middleware’dan marshrutga ma’lumot uzatishning odatiy usuli. Bu yondashuv middleware darsida ko’rilgan.

Marshrutga ulaymiz:

const { requireToken } = require("../middleware/token");

router.get("/me", requireToken, (request, response) => {
  response.json(User.findById(request.userId));
});

Sinash

curl -X POST http://localhost:3000/api/login -H "Content-Type: application/json" -d '{"email":"nodira@example.com","password":"kuchli-parol-123"}'
{"token":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VySWQiOjIsImlhdCI...","expiresIn":3600}

Tokenni nusxa olib, so’rovga qo’shing:

curl -i -H "Authorization: Bearer TOKEN_SHU_YERGA" http://localhost:3000/api/me
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8

{"id":2,"email":"nodira@example.com","createdAt":"2026-09-12 14:09:21"}

Tokensiz:

curl -i http://localhost:3000/api/me
HTTP/1.1 401 Unauthorized
Content-Type: application/json; charset=utf-8

{"error":"Token yuborilmadi"}

Tokenning oxiriga bitta harf qo’shib buzing:

HTTP/1.1 401 Unauthorized
Content-Type: application/json; charset=utf-8

{"error":"Token yaroqsiz"}

Imzo mos kelmadi. Payload’ni o’zgartirish urinishi ham aynan shu javobni beradi.

Sessiya yoki token — qaysi biri

Ikkalasi bir-birining o’rnini bosmaydi. Tanlov mijozga bog’liq.

Sessiya JWT
Ma’lumot qayerda Serverda Mijozda
Server xotirasi Har foydalanuvchiga Sarflanmaydi
Darhol bekor qilish Oson (destroy) Qiyin
Bir nechta server Umumiy ombor kerak O’zi ishlaydi
Mobil ilova va SPA Noqulayroq Qulay

Tokenni mijozda qayerda saqlash

Frontend tokenni olib, har so’rovga qo’shishi kerak:

const response = await fetch("/api/tasks", {
  headers: { Authorization: `Bearer ${token}` },
});

fetch sintaksisi fetch darsida ko’rilgan.

Saqlash joyi esa munozarali savol:

Joy Muammo
localStorage Har qanday JavaScript o’qiy oladi — XSS da token ketadi
httpOnly cookie JavaScript o’qiy olmaydi, lekin CSRF himoyasi kerak

httpOnly cookie xavfsizroq, lekin unda JWT ning “cookie’siz ishlaydi” degan asosiy afzalligi yo’qoladi. Shuning uchun oddiy qoida shu: brauzer ilovasi uchun sessiya, mobil ilova va tashqi API uchun token. XSS mexanizmi keyingi darsda ko’riladi.

Amaliy mashq

task-app loyihasida davom eting:

  1. jsonwebtoken ni o’rnatib, token yarating va uni nuqtalar bo’yicha uch qismga bo’lib chop eting;
  2. Payload’ni Buffer.from(..., "base64url") bilan ochib o’qing — maxfiy kalit kerak emasligini tasdiqlang;
  3. POST /api/login marshrutini yozib, javobda token olinishini ko’ring;
  4. requireToken middleware’ini yozib, /api/me ni himoyalang;
  5. Tokenning oxirgi belgisini o’zgartirib so’rang — Token yaroqsiz javobini oling;
  6. expiresIn: "5s" bilan token yarating, olti soniya kutib so’rang va Token muddati tugagan xabarini ko’ring.

2-qadam darsning asosiy xavfsizlik g’oyasini isbotlaydi: JWT shifrlanmaydi, faqat imzolanadi.

Qisqacha xulosa

  • JWT uch qismdan iborat: header, payload va imzo.
  • Payload shifrlanmaydi — har kim ochib o’qiy oladi, shuning uchun maxfiy ma’lumot solinmaydi.
  • Imzo ma’lumotni o’zgartirishni to’sadi: bitta belgi o’zgarsa token yaroqsiz bo’ladi.
  • expiresIn muddat belgilaydi; muddati tugagan token TokenExpiredError beradi.
  • Token Authorization: Bearer <token> sarlavhasida yuboriladi, maxfiy kalit esa kodda emas, muhit o’zgaruvchisida saqlanadi.
  • Berilgan tokenni bekor qilish qiyin — muddat qisqa bo’lsin yoki refresh token qo’shilsin.
  • Brauzer sayti uchun sessiya, mobil va tashqi API uchun token qulayroq.

Keyingi darsda fayl yuklash — multer bilan rasm qabul qilish va uni xavfsiz saqlash.

Bu dars foydali bo'ldimi?

marta ko'rildi