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:
jsonwebtokenni o’rnatib, token yarating va uni nuqtalar bo’yicha uch qismga bo’lib chop eting;- Payload’ni
Buffer.from(..., "base64url")bilan ochib o’qing — maxfiy kalit kerak emasligini tasdiqlang; POST /api/loginmarshrutini yozib, javobda token olinishini ko’ring;requireTokenmiddleware’ini yozib,/api/meni himoyalang;- Tokenning oxirgi belgisini o’zgartirib so’rang —
Token yaroqsizjavobini oling; expiresIn: "5s"bilan token yarating, olti soniya kutib so’rang vaToken muddati tugaganxabarini 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.
expiresInmuddat belgilaydi; muddati tugagan tokenTokenExpiredErrorberadi.- 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.