JWT (JSON Web Token)
JWT (JSON Web Token) — bu ma'lumotni imzolangan, ixcham va o'zini-o'zi tavsiflaydigan token sifatida uzatish standarti. U zamonaviy API'larda autentifikatsiya uchun keng qo'llaniladi. Ushbu darsda JWT tuzilishini, uning imzo orqali qanday himoyalanishini va Express'da login'dan himoyalangan route'gacha bo'lgan to'liq oqimni ko'rib chiqamiz.
JWT nima va u nimani hal qiladi?
Oldingi darsda ko'rgan edik: HTTP holatsiz, shuning uchun har so'rovda foydalanuvchini qayta taniymiz. JWT bu muammoni imzolangan token orqali hal qiladi. Server login vaqtida foydalanuvchi ma'lumotini o'z ichiga olgan tokenni imzolaydi va mijozga beradi. Mijoz uni har so'rovda qaytaradi. Server imzoni tekshiradi — agar imzo to'g'ri bo'lsa, token ichidagi ma'lumotga ishonadi.
Muhim jihat: token ichidagi ma'lumot shifrlanmagan, lekin imzolangan. Ya'ni har kim token ichini o'qiy oladi, ammo uni server sirini bilmasdan o'zgartira olmaydi — o'zgartirilsa, imzo mos kelmaydi.
JWT tuzilishi: uch qism
JWT nuqta bilan ajratilgan uchta qismdan iborat: header.payload.signature. Har bir qism alohida kodlangan matndir:
// JWT quyidagicha ko'rinadi (uch qism nuqta bilan ajratilgan):
// xxxxx.yyyyy.zzzzz
// | | |
// header payload signature
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjMiLCJyb2wiOiJ1c2VyIn0.aBcDeFg...
1. Header (sarlavha)
Qanday algoritm bilan imzolanganini ko'rsatadi:
{
"alg": "HS256",
"typ": "JWT"
}
2. Payload (foydali yuk)
Token ichidagi ma'lumot — "claims" deb ataladi. Bu foydalanuvchi identifikatori, roli va muddati kabi maydonlar:
{
"sub": "123", // foydalanuvchi ID (subject)
"rol": "user",
"iat": 1719800000, // yaratilgan vaqt (issued at)
"exp": 1719803600 // amal qilish muddati (expiration)
}
3. Signature (imzo)
Header va payload'ni maxfiy kalit bilan birga hashlashdan hosil bo'ladi. Imzo — bu tokenning butunligini kafolatlaydigan qism. Agar biror bayt o'zgartirilsa, imzo mos kelmay qoladi:
// Kontseptual tarzda imzo shunday hisoblanadi:
// HMACSHA256(
// base64url(header) + '.' + base64url(payload),
// MAXFIY_KALIT
// )
//
// MAXFIY_KALIT faqat serverda bo'ladi. Shuning uchun
// hech kim to'g'ri imzoni server sirisiz yasay olmaydi.
Express'da JWT: login → token
Endi to'liq oqimni ko'ramiz. Avval foydalanuvchi login qiladi, biz parolni tekshiramiz va muvaffaqiyatli bo'lsa, imzolangan token beramiz. Bu yerda jsonwebtoken kutubxonasi ishlatiladi:
const jwt = require('jsonwebtoken');
const bcrypt = require('bcrypt');
// Maxfiy kalit .env faylidan olinadi, kodga yozilmaydi!
const JWT_SIR = process.env.JWT_SECRET;
app.post('/login', async (req, res) => {
const { email, parol } = req.body;
const foydalanuvchi = await db.foydalanuvchiTop({ email });
// Bir xil mavhum xato (foydalanuvchi mavjudligini fosh qilmaslik)
if (!foydalanuvchi || !(await bcrypt.compare(parol, foydalanuvchi.parolHash))) {
return res.status(401).json({ xato: 'Email yoki parol xato' });
}
// Tokenni imzolaymiz. Payload'ga MAXFIY ma'lumot qo'ymaymiz.
const token = jwt.sign(
{ sub: foydalanuvchi.id, rol: foydalanuvchi.rol },
JWT_SIR,
{ expiresIn: '1h' } // token 1 soatdan keyin amal qilmaydi
);
res.json({ token });
});
expiresIn ni albatta belgilang. Muddatsiz token o'g'irlansa, u abadiy yaroqli qoladi. Qisqa muddat (masalan, 15 daqiqa - 1 soat) o'g'irlangan tokenning zarar oynasini kichraytiradi.Tokenni tekshirish: himoyalangan route middleware
Endi himoyalangan route'larni yaratamiz. Har bir himoyalangan so'rovda mijoz tokenni odatda Authorization sarlavhasida Bearer sxemasi bilan yuboradi. Middleware uni tekshiradi:
function tokenTekshir(req, res, next) {
const sarlavha = req.headers['authorization'];
// 'Bearer <token>' formatidan tokenni ajratib olamiz
if (!sarlavha || !sarlavha.startsWith('Bearer ')) {
return res.status(401).json({ xato: 'Token topilmadi' });
}
const token = sarlavha.slice(7); // 'Bearer ' dan keyingi qism
try {
// verify imzoni VA muddatni tekshiradi. Xato bo'lsa, exception tashlaydi.
const payload = jwt.verify(token, JWT_SIR);
req.foydalanuvchi = payload; // { sub, rol, iat, exp }
next();
} catch (e) {
// TokenExpiredError yoki JsonWebTokenError
return res.status(401).json({ xato: 'Token yaroqsiz yoki muddati o'tgan' });
}
}
// Himoyalangan route: faqat yaroqli token bilan kirish mumkin
app.get('/api/profil', tokenTekshir, async (req, res) => {
// req.foydalanuvchi.sub — tokendan olingan foydalanuvchi ID
const foydalanuvchi = await db.foydalanuvchiTopById(req.foydalanuvchi.sub);
res.json({ email: foydalanuvchi.email, rol: foydalanuvchi.rol });
});
// Avtorizatsiya bilan: faqat admin
function faqatAdmin(req, res, next) {
if (req.foydalanuvchi.rol !== 'admin') {
return res.status(403).json({ xato: 'Ruxsat yo'q' });
}
next();
}
app.delete('/api/foydalanuvchi/:id', tokenTekshir, faqatAdmin, async (req, res) => {
await db.foydalanuvchiOchir(req.params.id);
res.json({ muvaffaqiyat: true });
});
jwt.verify ni doim try/catch ichida chaqiring. Muddati o'tgan yoki soxta token exception tashlaydi. Agar verify o'rniga decode ishlatsangiz — bu xato: decode imzoni tekshirmaydi, shunchaki payload'ni o'qiydi. Har doim verify ishlating.Muddat va tokenni yangilash (refresh)
Qisqa muddatli access token xavfsizroq, lekin har soatda foydalanuvchini qayta login qildirish noqulay. Amaliyotda ko'pincha ikki tokenli sxema ishlatiladi:
- Access token: qisqa muddatli (masalan, 15 daqiqa), har so'rovda ishlatiladi;
- Refresh token: uzoqroq muddatli, xavfsiz saqlanadi (masalan,
HttpOnlycookie'da) va faqat yangi access token olish uchun ishlatiladi.
Access token muddati tugaganda, mijoz refresh token bilan yangi access token so'raydi. Refresh tokenni serverda kuzatib borish uni bekor qilish (masalan, chiqishda) imkonini beradi.
JWT: afzallik va kamchiliklari
JWT sehrli tayoqcha emas. Uni to'g'ri joyda ishlatish uchun kuchli va zaif tomonlarini biling:
Afzalliklari
- Holatsizlik: server har so'rovda bazaga murojaat qilmasdan tokenni tekshiradi — masshtablash oson;
- Turli mijozlar: web, mobil ilova va boshqa xizmatlar bir xil token bilan ishlaydi;
- O'zini-o'zi tavsiflaydi: foydalanuvchi ID va roli tokenning ichida.
Kamchiliklari
- Bekor qilish qiyin: imzolangan token muddati tugaguncha yaroqli qoladi; uni majburan bekor qilish uchun qo'shimcha mexanizm (qora ro'yxat yoki qisqa muddat) kerak;
- O'g'irlanish xavfi: token o'g'irlansa, uni ishlatgan har kim foydalanuvchi bo'lib ko'rinadi — shuning uchun HTTPS va xavfsiz saqlash zarur;
- Hajmi: token cookie yoki sessiya ID'dan kattaroq, har so'rovda yuboriladi.
localStorage'da saqlash keng tarqalgan, lekin xavfli: XSS bo'lsa, zararli skript localStorage'ni o'qiy oladi va tokenni o'g'irlaydi. Xavfsizroq variant — tokenni HttpOnly cookie'da saqlash (JS o'qiy olmaydi), ammo bu holda CSRF himoyasini (keyingi darsda) qo'shish kerak. Har ikki yondashuvning o'ziga xos xavfi bor.Xulosa
- JWT — imzolangan, uch qismli (
header.payload.signature) token; imzo uning butunligini kafolatlaydi; - Payload shifrlanmagan — unga maxfiy ma'lumot qo'ymang, faqat identifikator va rol;
- Login'da
jwt.signbilan token yasaymiz, himoyalangan route'dajwt.verifybilan tekshiramiz (hech qachondecodebilan emas); - Maxfiy kalit
.envda saqlanadi, kodga yozilmaydi; expiresInni albatta belgilang; qisqa access + uzoq refresh token sxemasi xavfsizlikni oshiradi;- Tokenni
HttpOnlycookie'da yoki xavfsiz saqlang;localStorageXSS'ga zaif.