Mundarija (34)
- 1. Kirish va motivatsiya
- 2. Nazariya — chuqur tushuntirish
- 2.1. Bitta token muammosi (takrorlash — 5.15)
- 2.2. Ikki token g'oyasi (access + refresh)
- 2.3. Token oqimi (umumiy rasm)
- 2.4. Refresh token rotation (rotatsiya) — muhim
- 2.5. Reuse detection (qayta ishlatishni aniqlash) — o'g'irlikni fosh qilish
- 2.6. Token bekor qilish (revocation)
- 2.7. Tokenlarni qayerda saqlash (eng xavfsiz — 14)
- 2.8. Refresh token'ni DB'da xavfsiz saqlash
- 2.9. Access va refresh muddatlari (qancha)
- 2.10. Silent refresh (foydalanuvchi sezmaydi)
- 2.11. Xavfsizlik amaliyotlari (14)
- 3. Sintaksis — tez ma'lumotnoma
- 4. Batafsil kod namunalari
- Misol 1 — Token yasash funksiyalari (2.2)
- Misol 2 — Login (ikki token beradi — 2.3)
- Misol 3 — Refresh endpoint (yangi access — 2.3, 2.4)
- Misol 4 — Logout (refresh bekor — 2.6)
- Misol 5 — Access token middleware (himoya — 5.15)
- Misol 6 — "Barcha qurilmadan chiqish" (2.6)
- Misol 7 — Frontend silent refresh (Axios interceptor — 2.10)
- Misol 8 — Parol o'zgarganda barcha tokenni bekor (2.6, 14)
- 5. To'g'ri va noto'g'ri holatlar
- 6. Keng tarqalgan xatolar va yechimlari
- 7. Integratsiya — bu mavzu stack'ning qayerida uchraydi
- 8. Eng yaxshi amaliyotlar (best practices)
- 9. Amaliy loyiha: "Access/Refresh Token Tizimi (rotatsiya bilan)"
- Maqsad
- Talablar (requirements)
- Maslahatlar (hint)
- "Tayyor" mezonlari (acceptance criteria)
- 10. Xulosa va keyingi bobga ko'prik
- Foydalanilgan rasmiy/ishonchli manbalar
Access va refresh token — JWT rotation va xavfsiz saqlash (5.16-bob)
5-QISM — Node.js Backend · 16-mavzu
1. Kirish va motivatsiya
5.15-bobda JWT bilan autentifikatsiyani o'rgandik va oxirida uning katta kamchiligini ko'rdik: JWT stateless — server uni eslamaydi, shuning uchun bekor qilib bo'lmaydi. Token o'g'irlansa yoki foydalanuvchi logout qilsa ham, token muddati tugaguncha amal qiladi. Bu — jiddiy xavfsizlik muammosi (14).
Yechim oddiy ko'rinadi: tokenni qisqa muddatli qilamiz (masalan 15 daqiqa) — o'g'irlansa, tez yaroqsiz bo'ladi. Lekin shunda boshqa muammo: foydalanuvchi har 15 daqiqada qayta login qilishi kerakmi? Yo'q — bu dahshatli UX. Bizga ikkalasi ham kerak: xavfsizlik (qisqa muddat) va qulaylik (uzoq "kirgan holda qolish").
Yechim — ikki token strategiyasi: qisqa muddatli access token (har so'rovda ishlatiladi) + uzoq muddatli refresh token (faqat yangi access token olish uchun). Bu — zamonaviy auth'ning standart yechimi (RFC 9700, 2026'da majburiy amaliyot). Bu bobda uni professional, xavfsiz darajada quramiz: token rotatsiyasi, qayta ishlatishni aniqlash (reuse detection), xavfsiz saqlash va bekor qilish.
O'xshatish: access token — mehmonxona xona kaliti (vaqtinchalik, tez muddati tugaydi, yo'qotsangiz katta zarar yo'q). Refresh token — pasport (qaltis, seyfda saqlanadi, faqat resepshnda yangi kalit olish uchun ko'rsatiladi). Har eshikda pasport emas, kalit ishlatasiz (access). Kalit muddati tugasa — resepshnga borib (refresh), pasport bilan yangi kalit olasiz. Pasport o'g'irlansa — uni bekor qilib (revoke), yangisini berishadi.
Nega muhim?
- 5.15 muammosini hal qiladi — qisqa access (xavfsiz) + uzoq refresh (qulay).
- Zamonaviy standart (14) — RFC 9700: rotatsiya majburiy; har real ilovada bor.
- O'g'irlikni aniqlash — reuse detection token o'g'irligini fosh qiladi.
- Intervyu/ish — "access va refresh token farqi" — klassik savol.
2. Nazariya — chuqur tushuntirish
2.1. Bitta token muammosi (takrorlash — 5.15)
Bitta JWT bilan ikki yomon variant bor:
Uzoq muddatli token (masalan 30 kun):
✓ Qulay (kam login)
✗ O'g'irlansa — 30 kun hacker kirib turadi (bekor qila olmaymiz! — 14)
Qisqa muddatli token (masalan 15 daqiqa):
✓ Xavfsiz (o'g'irlansa, tez tugaydi)
✗ Har 15 daqiqada qayta login (dahshatli UX)Ikkalasi ham yomon. Yechim — ikkisini birlashtirish: qisqa access + uzoq refresh 2.2-bob.
2.2. Ikki token g'oyasi (access + refresh)
ACCESS TOKEN — qisqa muddatli (15-60 daqiqa)
→ HAR so'rovda ishlatiladi (himoyalangan endpoint)
→ o'g'irlansa, tez yaroqsiz (xavf kam)
→ stateless JWT (server eslamaydi — tez tekshiriladi)
REFRESH TOKEN — uzoq muddatli (7-90 kun)
→ FAQAT yangi access token olish uchun (/refresh endpoint)
→ DB'da saqlanadi (bekor qilinishi mumkin — stateful!)
→ kamdan-kam ishlatiladi (har 15 daqiqada bir marta)Asosiy g'oya (descope/auth0): access token — tez-tez ishlatiladigan, lekin arzon (o'g'irlansa tez tugaydi). Refresh token — kam ishlatiladigan, lekin qimmat (uzoq), shuning uchun DB'da nazorat ostida (bekor qilinadi). Xavfsizlik (qisqa access) + qulaylik (uzoq refresh) — ikkalasi ham.
Access token payload'ida nima saqlanadi: faqat minimal, maxfiy bo'lmagan ma'lumot —
sub(foydalanuvchi ID),rol(RBAC uchun — 5.17), kerak bo'lsasub(2.2, Misol 1).
2.3. Token oqimi (umumiy rasm)
LOGIN:
email+parol → server: access (15min) + refresh (7kun) beradi
access → xotirada/cookie
refresh → httpOnly cookie + DB'ga saqlanadi 2.7-bob
HAR SO'ROV:
access token bilan → himoyalangan endpoint → ✓
ACCESS MUDDATI TUGADI (15min o'tdi):
so'rov → 401 (access eskirgan) →
client /refresh ga refresh token yuboradi →
server refresh'ni DB'da tekshiradi → YANGI access (+ yangi refresh — 2.4) →
client yangi access bilan davom etadi (foydalanuvchi sezmaydi!)
LOGOUT:
refresh token'ni DB'dan o'chir (bekor — 2.6) ┌──────┐ login ┌────────┐
│Client│─────────▶│ Server │ access(15m) + refresh(7d)
│ │◀─────────│ │
└──────┘ └────────┘
│ access bilan so'rovlar (15 daqiqa)
│ ...access tugadi → 401...
│ refresh bilan /refresh
▼
yangi access (+ yangi refresh) → davom2.4. Refresh token rotation (rotatsiya) — muhim
Token rotation — har refresh ishlatilganda, yangi refresh token ham beriladi, eskisi bekor qilinadi (authjs/okta, RFC 9700):
Refresh R1 ishlatildi → yangi access + yangi refresh R2
→ R1 BEKOR qilinadi (endi ishlamaydi)
Keyingi safar R2 ishlatiladi → R3, R2 bekor
...Nega rotatsiya (14): refresh token uzoq muddatli — o'g'irlansa xavfli. Rotatsiya bilan har refresh bir martalik bo'ladi. Bu — reuse detectionga 2.5-bob imkon beradi: eski (allaqachon ishlatilgan) refresh qayta ishlatilsa — o'g'irlik signali. 2026'da rotatsiya majburiy (RFC 9700).
2.5. Reuse detection (qayta ishlatishni aniqlash) — o'g'irlikni fosh qilish
Eng kuchli xavfsizlik mexanizmi: agar allaqachon ishlatilgan (bekor qilingan) refresh token qayta ishlatilsa — bu o'g'irlik belgisi (descope/auth0):
Normal: R1 → R2 → R3 (har biri bir marta)
O'G'IRLIK stsenariysi:
Hacker R1'ni o'g'irladi. Lekin haqiqiy foydalanuvchi ham R1'ni ishlatdi → R2 oldi (R1 bekor)
Hacker R1'ni ishlatmoqchi → R1 ALLAQACHON BEKOR → REUSE DETECTED!
→ butun token oilasini (R1,R2,R3...) BEKOR QILISH → ikkalasi ham qayta login qilsin (14)Token family (oila): bir login'dan kelib chiqqan barcha refresh tokenlar — bitta "oila". Reuse aniqlansa, butun oila bekor qilinadi (faqat bitta token emas). Bu — o'g'irlangan tokenni "uzoq muddatli kirish"dan "aniqlanadigan hodisa"ga aylantiradi (manbalar).
2.6. Token bekor qilish (revocation)
Refresh token DB'da saqlangani uchun, uni bekor qilish mumkin (access — stateless, bekor qilib bo'lmaydi, lekin qisqa):
Logout → o'sha refresh'ni DB'dan o'chirish
"Barcha qurilmadan chiq" → foydalanuvchining BARCHA refresh'larini o'chirish
Parol o'zgardi → barcha refresh'ni bekor qilish (xavfsizlik — 14)
O'g'irlik aniqlandi → token oilasini bekor qilish (2.5)Access token bekor qilish: stateless JWT bekor qilinmaydi. Lekin qisqa (15min) — tez tugaydi. Agar darhol bekor kerak bo'lsa — Redis blacklist (bekor qilingan access tokenlar, qisqa muddatga — 5.21).
2.7. Tokenlarni qayerda saqlash (eng xavfsiz — 14)
Eng xavfsiz strategiya (curity/auth.js):
Access token → XOTIRADA (JS o'zgaruvchi/React state — 11)
yoki httpOnly cookie
→ qisqa muddatli, sahifa yangilashda yo'qoladi (refresh bilan tiklanadi)
Refresh token → httpOnly + Secure + SameSite cookie (14, 5.15)
→ JS o'qiy olmaydi (XSS himoyasi); DB'da nusxasi (bekor uchun)Refresh token — eng qimmat, eng himoyalangan (14): httpOnly cookie'da (JS ko'rmaydi — XSS himoyasi);
localStorageda hech qachon 5.15-bob. DB'da hash qilib saqlash (parol kabi — bcrypt — 2.8) yanada xavfsiz (DB sizsa, tokenlar ochiq bo'lmaydi).
2.8. Refresh token'ni DB'da xavfsiz saqlash
Refresh token DB'da saqlanadi (bekor uchun — 2.6). Lekin uni ochiq saqlash xavfli (DB sizsa). Hash qilib saqlash (parol kabi — 5.15):
refresh_tokens jadvali:
| id | userId | tokenHash | family | expiresAt | revoked |
| 1 | 7 | hash(token) | fam-1 | +7kun | false |
→ tokenning O'ZI emas, HASH'i (DB sizsa, ishlatib bo'lmaydi — 14)
→ family: reuse detection uchun 2.5-bob; revoked: bekor belgisi (2.6)2.9. Access va refresh muddatlari (qancha)
Tavsiya etilgan muddatlar (guptadeepak/CIAM 2026):
Access token: 15 daqiqa – 1 soat (qisqa — xavfsizlik)
Refresh token: 7 – 30 kun (web); 30-90 kun (mobil app)
Sezgir (bank): qisqaroq (access 5-15min)Balans: qisqaroq access — xavfsizroq, lekin ko'proq refresh so'rovi. 15 daqiqa — ko'p ilova uchun yaxshi balans. Refresh muddatini loyiha (sezgirlik) bo'yicha tanlang.
2.10. Silent refresh (foydalanuvchi sezmaydi)
Yaxshi UX: access token tugaganda, foydalanuvchi sezmasdan yangilanishi kerak. Frontend (11) buni avtomatik qiladi:
So'rov → 401 (access tugagan) →
frontend interceptor (Axios — 2.18-JS) ushlaydi →
/refresh ga so'rov (refresh cookie avtomatik) →
yangi access olinadi →
asl so'rov YANGI access bilan QAYTA yuboriladi →
foydalanuvchi hech narsa sezmaydi (uzluksiz)Bu — frontend mas'uliyati (11, Axios interceptor — 2.18-JS), lekin backend
/refreshendpoint'ini to'g'ri berishi kerak. Backend + frontend birga ishlaydi.
2.11. Xavfsizlik amaliyotlari (14)
✓ Access qisqa (15-60min), refresh uzoq (7-30kun) — 2.9
✓ Refresh rotatsiya (har ishlatishda yangi — 2.4); reuse detection 2.5-bob
✓ Refresh httpOnly cookie + DB'da hash (2.7, 2.8)
✓ Logout/parol o'zgarishida refresh bekor 2.6-bob
✓ Access va refresh uchun ALOHIDA secret 5.8-bob
✓ Refresh endpoint'iga rate limiting 5.20-bob
✓ HTTPS (14); refresh oilasini kuzat (o'g'irlik — 2.5)3. Sintaksis — tez ma'lumotnoma
import jwt from "jsonwebtoken";
// Ikki token yasash (2.2)
const access = jwt.sign({ sub: id, rol }, ACCESS_SECRET, { expiresIn: "15m" });
const refresh = jwt.sign({ sub: id }, REFRESH_SECRET, { expiresIn: "7d" });
// Refresh oqimi (2.3)
// 1. refresh'ni verify 2. DB'da tekshir (bekor emasmi) 3. rotatsiya (yangi refresh)
// 4. yangi access ber
// Saqlash (2.7)
res.cookie("refreshToken", refresh, { httpOnly: true, secure: true, sameSite: "lax", path: "/api/auth/refresh" });4. Batafsil kod namunalari
Misol 1 — Token yasash funksiyalari (2.2)
import jwt from "jsonwebtoken";
import { config } from "../config/index.js"; // (5.8)
// Access — qisqa, asosiy ma'lumot bilan (2.2)
export const accessYasash = (user) =>
jwt.sign(
{ sub: user.id, rol: user.rol }, // payload (5.15)
config.jwt.accessSecret, // ALOHIDA secret (2.11)
{ expiresIn: "15m" } // qisqa (2.9)
);
// Refresh — uzoq, minimal ma'lumot (2.2)
export const refreshYasash = (user) =>
jwt.sign(
{ sub: user.id }, // faqat ID
config.jwt.refreshSecret, // boshqa secret (2.11)
{ expiresIn: "7d" } // uzoq (2.9)
);Misol 2 — Login (ikki token beradi — 2.3)
import bcrypt from "bcrypt";
export const login = async (req, res, next) => {
try {
const { email, parol } = req.body;
const user = await User.findOne({ email }).select("+parol"); // (5.15)
if (!user || !(await bcrypt.compare(parol, user.parol))) {
return res.status(401).json({ error: "Email yoki parol noto'g'ri" }); // (5.15)
}
// Ikki token (2.2)
const accessToken = accessYasash(user);
const refreshToken = refreshYasash(user);
// Refresh'ni DB'da hash qilib saqlash (2.8)
await RefreshToken.create({
userId: user.id,
tokenHash: await bcrypt.hash(refreshToken, 10), // hash (DB sizsa — 14)
family: crypto.randomUUID(), // oila (2.5)
expiresAt: new Date(Date.now() + 7 * 24 * 3600 * 1000),
});
// Refresh — httpOnly cookie (2.7)
res.cookie("refreshToken", refreshToken, {
httpOnly: true, secure: config.isProd, sameSite: "lax",
path: "/api/auth", // faqat auth route'larida (2.7)
maxAge: 7 * 24 * 3600 * 1000,
});
// Access — javobda (frontend xotirada saqlaydi — 2.7)
res.json({ accessToken, user: { id: user.id, email: user.email, rol: user.rol } });
} catch (err) { next(err); }
};Misol 3 — Refresh endpoint (yangi access — 2.3, 2.4)
import jwt from "jsonwebtoken";
import bcrypt from "bcrypt";
export const refresh = async (req, res, next) => {
try {
const token = req.cookies.refreshToken; // cookie'dan (2.7)
if (!token) return res.status(401).json({ error: "Refresh token yo'q" });
// 1. Imzoni tekshirish (2.2)
let payload;
try {
payload = jwt.verify(token, config.jwt.refreshSecret);
} catch {
return res.status(401).json({ error: "Refresh noto'g'ri/tugagan" });
}
// 2. DB'da topish va tekshirish (bekor emasmi — 2.6)
const saqlangan = await RefreshToken.findOne({ userId: payload.sub, revoked: false });
if (!saqlangan || !(await bcrypt.compare(token, saqlangan.tokenHash))) {
// REUSE DETECTION: bekor qilingan token qayta ishlatildi → o'g'irlik 2.5-bob!
await RefreshToken.updateMany({ userId: payload.sub }, { revoked: true }); // butun oila (2.5)
return res.status(401).json({ error: "Xavfsizlik buzilishi — qayta kiring" });
}
// 3. ROTATSIYA: eskini bekor qilish, yangi refresh berish (2.4)
saqlangan.revoked = true;
await saqlangan.save();
const user = await User.findById(payload.sub);
const yangiRefresh = refreshYasash(user);
await RefreshToken.create({
userId: user.id, tokenHash: await bcrypt.hash(yangiRefresh, 10),
family: saqlangan.family, expiresAt: new Date(Date.now() + 7 * 24 * 3600 * 1000),
});
res.cookie("refreshToken", yangiRefresh, {
httpOnly: true, secure: config.isProd, sameSite: "lax", path: "/api/auth",
maxAge: 7 * 24 * 3600 * 1000,
});
// 4. Yangi access berish (2.3)
res.json({ accessToken: accessYasash(user) });
} catch (err) { next(err); }
};Misol 4 — Logout (refresh bekor — 2.6)
export const logout = async (req, res, next) => {
try {
const token = req.cookies.refreshToken;
if (token) {
const payload = jwt.decode(token); // (5.15)
// DB'dan o'chir/bekor qil (2.6)
await RefreshToken.updateMany({ userId: payload?.sub }, { revoked: true });
}
res.clearCookie("refreshToken", { path: "/api/auth" }); // cookie tozalash (5.15)
res.json({ message: "Tizimdan chiqdingiz" });
} catch (err) { next(err); }
};Misol 5 — Access token middleware (himoya — 5.15)
import jwt from "jsonwebtoken";
export const auth = (req, res, next) => {
const token = req.headers.authorization?.startsWith("Bearer ")
? req.headers.authorization.slice(7) // header'dan (access — 2.7)
: null;
if (!token) return res.status(401).json({ error: "Avtorizatsiya kerak" });
try {
const payload = jwt.verify(token, config.jwt.accessSecret); // access secret (2.11)
req.user = { id: payload.sub, rol: payload.rol };
next();
} catch (err) {
// Muddat tugagan bo'lsa — maxsus kod (frontend refresh qilsin — 2.10)
if (err.name === "TokenExpiredError") {
return res.status(401).json({ error: "Access tugagan", code: "TOKEN_EXPIRED" });
}
return res.status(401).json({ error: "Token noto'g'ri" });
}
};Misol 6 — "Barcha qurilmadan chiqish" (2.6)
export const hammadanChiq = async (req, res, next) => {
try {
// Foydalanuvchining BARCHA refresh tokenlarini bekor qilish (2.6)
await RefreshToken.updateMany({ userId: req.user.id }, { revoked: true });
res.clearCookie("refreshToken", { path: "/api/auth" });
res.json({ message: "Barcha qurilmalardan chiqildi" });
// Endi hech bir qurilmada refresh ishlamaydi (access'lar 15min ichida tugaydi)
} catch (err) { next(err); }
};Misol 7 — Frontend silent refresh (Axios interceptor — 2.10)
// frontend (11, 2.18-JS) — backend uchun kontekst
import axios from "axios";
const api = axios.create({ baseURL: "/api", withCredentials: true }); // cookie uchun
// Har so'rovga access token qo'sh (xotiradan)
api.interceptors.request.use((cfg) => {
if (accessToken) cfg.headers.Authorization = `Bearer ${accessToken}`;
return cfg;
});
// 401 (access tugagan) bo'lsa — avtomatik refresh + qayta urinish (2.10)
api.interceptors.response.use(null, async (error) => {
if (error.response?.status === 401 && error.response.data.code === "TOKEN_EXPIRED") {
const { data } = await api.post("/auth/refresh"); // refresh cookie avtomatik
accessToken = data.accessToken; // yangi access (xotirada)
error.config.headers.Authorization = `Bearer ${accessToken}`;
return api(error.config); // asl so'rovni qayta yuborish
}
return Promise.reject(error);
});Misol 8 — Parol o'zgarganda barcha tokenni bekor (2.6, 14)
export const parolOzgartir = async (req, res, next) => {
try {
const user = await User.findById(req.user.id).select("+parol");
if (!(await bcrypt.compare(req.body.eskiParol, user.parol))) {
return res.status(401).json({ error: "Eski parol noto'g'ri" });
}
user.parol = await bcrypt.hash(req.body.yangiParol, 12); // (5.15)
await user.save();
// Xavfsizlik: barcha refresh'ni bekor qilish (boshqa qurilmalar chiqsin — 2.6, 14)
await RefreshToken.updateMany({ userId: user.id }, { revoked: true });
res.clearCookie("refreshToken", { path: "/api/auth" });
res.json({ message: "Parol o'zgartirildi. Qaytadan kiring." });
} catch (err) { next(err); }
};5. To'g'ri va noto'g'ri holatlar
1) Faqat bitta uzoq muddatli token
❌ bitta 30 kunlik token → o'g'irlansa bekor qila olmaysiz (2.1, 14)
✅ qisqa access + uzoq refresh (DB'da, bekor qilinadi)2) Refresh token'ni localStorage'da
❌ localStorage → XSS o'g'irlaydi (refresh — eng qimmat! — 2.7, 14)
✅ httpOnly cookie + DB'da hash3) Rotatsiyasiz refresh
❌ bir refresh qayta-qayta ishlatiladi → reuse detection imkonsiz 2.4-bob
✅ har refresh'da yangi (rotatsiya) + eski bekor4) Refresh'ni DB'da ochiq saqlash
// ❌ DB sizsa — tokenlar ochiq (14, 2.8)
await RefreshToken.create({ token: refreshToken });
// ✅ hash
await RefreshToken.create({ tokenHash: await bcrypt.hash(refreshToken, 10) });5) Access va refresh uchun bitta secret
// ❌ bitta secret (2.11)
jwt.sign(p, SECRET); // ikkalasi ham
// ✅ alohida (access secret sizsa, refresh xavfsiz)
jwt.sign(p, ACCESS_SECRET); jwt.sign(p, REFRESH_SECRET);6. Keng tarqalgan xatolar va yechimlari
Xato 1 — Refresh ishlamaydi (cookie kelmaydi)
Sababi: cookie path mos emas, yoki frontend withCredentials/CORS credentials yo'q 5.20-bob. Yechimi: path to'g'ri (/api/auth); withCredentials: true; CORS credentials: true.
Xato 2 — Har 15 daqiqada logout bo'lib qoladi
Sababi: refresh oqimi yo'q yoki frontend 401'da refresh qilmaydi 2.10-bob. Yechimi: Axios interceptor (Misol 7); /refresh endpoint.
Xato 3 — Reuse detection xato ishlaydi (normal foydalanuvchi chiqib ketadi)
Sababi: parallel so'rovlar (ikki tab) bir refresh'ni bir vaqtda ishlatdi. Yechimi: qisqa "grace period"; yoki bitta refresh so'rovini navbatlash (frontend); family logikasini ehtiyotkorlik bilan qo'llash.
Xato 4 — Logout'dan keyin ham access ishlaydi
Sababi: access stateless — bekor qilib bo'lmaydi 2.6-bob. Yechimi: bu normal (access 15min'da tugaydi); darhol kerak bo'lsa — Redis blacklist 5.21-bob.
Xato 5 — TokenExpiredError access uchun
Sababi: access muddati tugagan (kutilgan — 2.9). Yechimi: frontend refresh qilsin (code: TOKEN_EXPIRED — Misol 5, 7).
7. Integratsiya — bu mavzu stack'ning qayerida uchraydi
- Autentifikatsiya 5.15-bob: bu uni davom ettiradi (JWT, bcrypt, cookie).
- Env 5.8-bob: access/refresh alohida secret.
- Error handling 5.10-bob: 401, TOKEN_EXPIRED.
- RBAC 5.17-bob: access payload'dagi rol.
- Rate limiting 5.20-bob: refresh/login himoyasi.
- Redis 5.21-bob: access blacklist; refresh saqlash.
- DB (6): refresh_tokens jadvali (hash, family, revoked).
- Axios (2.18-JS): frontend interceptor — silent refresh.
- React (11): access xotirada, refresh cookie.
- NestJS 8.16-bob: JWT strategy, refresh guard — shu g'oya.
8. Eng yaxshi amaliyotlar (best practices)
- Qisqa access (15-60min) + uzoq refresh (7-30kun — 2.2, 2.9).
- Refresh rotatsiya (har ishlatishda yangi — 2.4); reuse detection + family bekor (2.5, 14).
- Refresh httpOnly cookie + DB'da hash (2.7, 2.8, 14); access xotirada.
- Alohida secret access va refresh uchun (2.11, 5.8).
- Logout/parol o'zgarishi — refresh bekor 2.6-bob; "barcha qurilmadan chiq".
- Silent refresh (frontend interceptor — 2.10) — yaxshi UX.
- Refresh/login'ga rate limiting (5.20, 14).
code: TOKEN_EXPIRED— frontend refresh signali (Misol 5).- Darhol bekor kerak bo'lsa — Redis access blacklist (2.6, 5.21).
- HTTPS (production — 14).
9. Amaliy loyiha: "Access/Refresh Token Tizimi (rotatsiya bilan)"
Professional token strategiyasini mustahkamlash.
Maqsad
Access + refresh token, rotatsiya, reuse detection va xavfsiz saqlash bilan to'liq token tizimini qurish (5.15 auth'ini kengaytirib).
Talablar (requirements)
- Login: access (15min) + refresh (7kun); refresh httpOnly cookie + DB'da hash (Misol 2, 2.7, 2.8).
- Refresh endpoint: verify → DB tekshir → rotatsiya (yangi refresh, eski bekor) → yangi access (Misol 3, 2.4).
- Reuse detection: bekor qilingan refresh ishlatilsa → butun oilani bekor (Misol 3, 2.5).
- Logout: refresh bekor + cookie tozalash (Misol 4, 2.6).
- Access middleware: verify; TokenExpiredError →
code: TOKEN_EXPIRED(Misol 5). - "Barcha qurilmadan chiqish": barcha refresh bekor (Misol 6, 2.6).
- Parol o'zgarishida: barcha refresh bekor (Misol 8, 14).
- Alohida secret access va refresh uchun (.env — 2.11, 5.8).
- (Bonus) Frontend silent refresh: Axios interceptor (Misol 7, 2.10).
- (Bonus) Refresh endpoint'iga rate limiting 5.20-bob.
Maslahatlar (hint)
- Ikki secret:
ACCESS_SECRET,REFRESH_SECRET2.11-bob. - Refresh DB:
{ userId, tokenHash, family, expiresAt, revoked }2.8-bob. - Rotatsiya: eski
revoked = true, yangi yarat 2.4-bob. - Reuse: topilmagan/bekor refresh →
updateMany({ userId }, { revoked: true })2.5-bob. - Cookie
path: "/api/auth"(faqat auth route — 2.7). - 401'da
code: TOKEN_EXPIRED(frontend refresh — Misol 5).
"Tayyor" mezonlari (acceptance criteria)
- Login access + refresh beradi (refresh cookie + DB hash).
- Refresh endpoint yangi access beradi (rotatsiya bilan).
- Eski refresh ishlamaydi (rotatsiya); reuse → oila bekor.
- Logout refresh'ni bekor qiladi.
- Access muddati tugaganda TOKEN_EXPIRED qaytadi.
- "Barcha qurilmadan chiqish" ishlaydi.
- Parol o'zgarishida tokenlar bekor.
- Access va refresh alohida secret.
- (Bonus) Frontend avtomatik refresh / rate limit.
Yechim kodi ataylab berilmagan — bu loyihani o'zingiz yozib ko'ring.
10. Xulosa va keyingi bobga ko'prik
Bu bobda zamonaviy auth'ning standart yechimini — access/refresh token strategiyasini — chuqur o'rgandik:
- Bitta token muammosi (uzoq — xavfli, qisqa — yomon UX — 2.1) → ikki token (access qisqa + refresh uzoq — 2.2).
- Oqim 2.3-bob: access har so'rovda; tugasa — refresh bilan yangilanadi (silent — 2.10).
- Rotatsiya (har refresh'da yangi — 2.4) + reuse detection (o'g'irlikni fosh, oilani bekor — 2.5) — RFC 9700 majburiy.
- Bekor qilish (logout/parol/o'g'irlik — 2.6); saqlash (refresh httpOnly cookie + DB hash; access xotira — 2.7, 2.8).
- Muddatlar (access 15-60min, refresh 7-30kun — 2.9); alohida secret; xavfsizlik (2.11, 14).
Keyingi bob — 5.17-bob: Authorization — RBAC (role-based access control). Foydalanuvchini aniqlash (authentication — 5.15, 5.16) tugadi; endi avtorizatsiya — "kimga nimaga ruxsat bor?" — ga o'tamiz. RBAC (rollarga asoslangan ruxsat): user/admin/moderator rollari, ruxsatlarni tekshiruvchi middleware, rol iyerarxiyasi va dinamik ruxsatlar — chuqur o'rganamiz.
Foydalanilgan rasmiy/ishonchli manbalar
- Auth.js — Refresh Token Rotation; Auth0 — Refresh Tokens; Okta — refresh token rotation
- Descope — Refresh Token Rotation & reuse detection; RFC 9700 (OAuth 2.0 Security BCP 2025)
- Curity / CIAM Compass — token storage & lifetime best practices 2026
O'qiganingizni mustahkamlang
Izohlar (0)
Izoh yozish uchun kiring.
- Hozircha izoh yo'q. Birinchi bo'ling!