5.16-bob: Access/Refresh tokens, token strategiyasi
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 qilolmaymiz! — 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 QIL 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'chir
"Barcha qurilmadan chiq" foydalanuvchining BARCHA refresh'larini o'chir
Parol o'zgardi barcha refresh'ni bekor qil (xavfsizlik — 14)
O'g'irlik aniqlandi token oilasini bekor (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 sakla (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 tekshir (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 qil, yangi refresh ber (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 ber (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 qil (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 yubor
}
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 (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 qilolmaysiz (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)
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 ehtiyotkor.
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
Izohlar (0)
Izoh yozish uchun kiring.
- Hozircha izoh yo'q. Birinchi bo'ling!