13.9-bob: Autentifikatsiya (NextAuth / Auth.js)
13-QISM — Next.js · 9-mavzu
1. Kirish va motivatsiya
Deyarli har real ilova bitta savolga javob berishi kerak: "Bu foydalanuvchi kim?" Onlayn do'kon (kim xarid qiladi, savatda nima), ijtimoiy tarmoq (kimning profili), bank ilovasi (kimning puli), admin panel (kim boshqaradi) — bularning hammasi autentifikatsiya (foydalanuvchini tanish — login/ro'yxat) va avtorizatsiya (u nima qila oladi — ruxsatlar)ga muhtoj. Bu — web ilovaning eng nozik, eng xavfsizlik talab qiladigan qismi (xato qilsangiz — foydalanuvchi ma'lumotlari o'g'irlanadi, hisoblar buziladi). Shuning uchun o'zingiz noldan yozish o'rniga (xavfli — ko'p nozik joy bor) sinab ko'rilgan kutubxona ishlatish maqsadga muvofiq: Next.js'da bu Auth.js (eski nomi NextAuth.js).
Auth.js — Next.js uchun eng mashhur, ishonchli autentifikatsiya yechimi. U murakkab narsani (sessiya boshqaruvi, OAuth oqimi, CSRF himoya, token) sizning o'rningizga qiladi, sizga esa sodda API beradi. U ko'p login usulini qo'llab-quvvatlaydi: ijtimoiy login (Google, GitHub bilan — "Google bilan kirish" tugmasi — foydalanuvchi parol eslab qolishi shart emas), email/parol (an'anaviy), va "sehrli havola" (email'ga havola — parolsiz). Va u Next.js bilan chuqur integratsiyalangan: server'da sessiyani olish (auth()), client'da (useSession), middleware bilan himoya 13.6-bob, Server Actions himoyasi 13.5-bob.
Bu bob: autentifikatsiya asoslari (authn vs authz), Auth.js sozlash, provayderlar (OAuth — Google/GitHub, Credentials — email/parol), sessiya strategiyasi (JWT vs database), sessiyani olish (server auth(), client useSession), sahifani himoya (middleware + server — 13.6), Server Action/Route himoyasi, rollar (admin/foydalanuvchi), callbacklar (jwt, session), kirish/chiqish, va xavfsizlik (CSRF, parol — bcrypt). Har mavzu to'liq, har kod misolida maqsad + izoh + "nima qiladi" bilan ochib beriladi.
O'xshatish: Autentifikatsiya va avtorizatsiya — bu klubga kirish va VIP zona. Autentifikatsiya (authn — "kimsan?") — bu eshik oldidagi qorovul: u sizning kimligingizni tekshiradi (pasport — parol, yoki taklif kartasi — Google login). Tasdiqlansa — klubga kirasiz (sessiya — qo'lingizga bilaguzuk taqishadi, endi har xonada qayta pasport ko'rsatish shart emas). Avtorizatsiya (authz — "nima qila olasiz?") — bu VIP zona qorovuli: siz klubga kirdingiz (autentifikatsiya), lekin VIP zonaga faqat VIP bilaguzukli odamlar kira oladi (rol — admin). Oddiy mehmon (foydalanuvchi) raqs maydonida (oddiy sahifalar), VIP (admin) yuqori qavatda (admin panel). Auth.js — bu professional xavfsizlik kompaniyasi (siz o'zingiz qorovul yollab, bilaguzuk tizimini o'ylab topish o'rniga — tayyor, sinagan tizimni ishlatasiz). O'zingiz qilganda bir teshik qoldirsa — butun klub xavf ostida (ma'lumot o'g'irlanadi); professional kompaniya bularni hisobga olgan.
Nega muhim?
- Har real ilovada kerak — foydalanuvchi tizimi (login, profil, shaxsiy ma'lumot) deyarli har loyihada.
- Xavfsizlik kritik — autentifikatsiya xatosi = ma'lumot o'g'irlanishi (o'zingiz yozish xavfli — kutubxona xavfsizroq).
- Auth.js soddalashtiradi — OAuth, sessiya, CSRF — murakkab narsani tayyor beradi.
- Next.js integratsiya — server/client/middleware/Server Actions — hammasi bilan ishlaydi.
2. Nazariya — chuqur tushuntirish
2.1. Autentifikatsiya vs avtorizatsiya
IKKI TUSHUNCHA (ko'p chalkashtiriladi — aniq farq):
AUTENTIFIKATSIYA (Authentication — "KIMSAN?"):
foydalanuvchini TANISH (login, ro'yxat — kim ekanini tasdiqlash)
parol, Google login, token — "bu haqiqatan Ali"
AVTORIZATSIYA (Authorization — "NIMA QILA OLASAN?"):
ruxsatlar (autentifikatsiyadan KEYIN — kim ekanini bilgach)
"Ali admin admin panelga kira oladi"; "Vali oddiy faqat o'z profili"
OQIM:
1. Autentifikatsiya: kim? (login Ali)
2. Avtorizatsiya: Ali nima qila oladi? (rol admin ruxsat)
┌────────────────────────────────────────────────────────────┐
│ Authn: KIMSAN (login) | Authz: NIMA QILA OLASAN (ruxsat) │
│ avval authn (tanish), keyin authz (ruxsat tekshir) │
└────────────────────────────────────────────────────────────┘
Authn (kimsan — login) ≠ Authz (nima qila olasan — rol/ruxsat)
Avval autentifikatsiya (tanish), keyin avtorizatsiya (ruxsat) — ikkalasi ham kerakAutentifikatsiya vs avtorizatsiya — ikki asosiy, lekin ko'p chalkashtiriladigan tushuncha. Autentifikatsiya (Authentication — qisqa "authn") — "kimsan?" — foydalanuvchini tanish (login/ro'yxat orqali kim ekanini tasdiqlash): parol, Google login, token bilan "bu haqiqatan Ali" ekanini aniqlash. Avtorizatsiya (Authorization — "authz") — "nima qila olasiz?" — ruxsatlar (autentifikatsiyadan keyin — kim ekanini bilgach): "Ali admin admin panelga kira oladi", "Vali oddiy foydalanuvchi faqat o'z profilini tahrir qila oladi". Oqim: (1) avval autentifikatsiya (kim? — login "Ali"); (2) keyin avtorizatsiya (Ali nima qila oladi? — rol admin ruxsat tekshir). Ya'ni avval tanish (authn), keyin ruxsat (authz). Misol: siz bankda — autentifikatsiya (pasport — kim ekaningiz), avtorizatsiya (faqat o'z hisobingizga kirish — boshqa odamnikiga emas). Ikki nuqta: (1) authn (kimsan — login) ≠ authz (nima qila olasiz — rol/ruxsat) — bular boshqa-boshqa narsa (chalkashtirmaslik kerak); (2) avval autentifikatsiya (tanish), keyin avtorizatsiya (ruxsat) — ikkalasi ham kerak (faqat login yetarli emas — kim nima qila olishini ham tekshirish kerak). Bu farqni tushunish — xavfsiz ilovaning asosi (13.5: 2.11, 13.6: Misol 10'da Server Action/Route'da avtorizatsiya tekshirdik — endi to'liq tizim). Auth.js asosan autentifikatsiyani (login) qiladi, avtorizatsiya (rol/ruxsat)ni esa siz qo'shasiz (callbacklar + tekshiruv — 2.9). Bu — har xavfsizlik suhbatining boshlanishi.
2.2. Auth.js (NextAuth) — nima va sozlash
AUTH.JS (NextAuth v5) — Next.js uchun autentifikatsiya kutubxonasi:
// auth.ts (loyiha ildizida — markaziy sozlama)
import NextAuth from "next-auth";
import GitHub from "next-auth/providers/github";
export const { handlers, auth, signIn, signOut } = NextAuth({
providers: [GitHub], // login usullari 2.3-bob
// sozlamalar (session, callbacks — 2.6, 2.9)
});
// app/api/auth/[...nextauth]/route.ts — Auth.js endpoint (OAuth oqimi):
import { handlers } from "@/auth";
export const { GET, POST } = handlers; // Auth.js o'z route'ini boshqaradi
AUTH.JS NIMA BERADI:
handlers — auth API endpoint (OAuth oqimi, callback)
auth() — sessiyani olish (server'da — 2.5)
signIn/signOut — kirish/chiqish funksiyalari 2.8-bob
Sessiya, CSRF, token — avtomatik (xavfsizlik)
Auth.js — markaziy auth.ts (NextAuth() sozlama); handlers route'da; auth/signIn/signOut export
Murakkab narsani (OAuth, sessiya, CSRF) avtomatik qiladi — siz sozlamani berasizAuth.js (NextAuth) — nima va sozlash — Next.js'ning standart autentifikatsiya yechimi. Auth.js (v5 — eski nomi NextAuth.js) — Next.js uchun eng mashhur autentifikatsiya kutubxonasi. Sozlash:
auth.tsfaylda (loyiha ildizida — markaziy)NextAuth({...})chaqiriladi va u to'rt narsani qaytaradi:handlers(auth API endpoint),auth(sessiyani olish),signIn/signOut(kirish/chiqish).providers— login usullari (GitHub, Google, email/parol — 2.3). Keyinapp/api/auth/[...nextauth]/route.tsdahandlersni export qilinadi (export const { GET, POST } = handlers) — bu Auth.js'ga o'z route'ini (OAuth oqimi, callback, sessiya) boshqarishga imkon beradi ([...nextauth]— catch-all — 13.2: 2.2 — Auth.js'ning barcha auth yo'llari). Auth.js nima beradi: (1)handlers— auth API endpoint (OAuth oqimi, callback — avtomatik); (2)auth()— sessiyani olish (server'da — 2.5); (3)signIn/signOut— kirish/chiqish funksiyalari 2.8-bob; (4) sessiya, CSRF himoya, token — avtomatik (xavfsizlik — siz o'ylamaysiz). Ikki nuqta: (1) Auth.js — markaziyauth.ts(NextAuth()sozlama),handlersroute'da,auth/signIn/signOutexport (markaziy konfiguratsiya); (2) murakkab narsani (OAuth oqimi, sessiya boshqaruvi, CSRF himoya, token) avtomatik qiladi — siz faqat sozlamani (provayderlar, callbacklar) berasiz. Bu — autentifikatsiyani o'zingiz noldan yozishdan (xavfli — ko'p nozik joy) qutqaradi (sinagan, xavfsiz kutubxona). Auth.js — Next.js auth'ning "de-fakto standarti".
2.3. Provayderlar (OAuth, Credentials)
PROVAYDERLAR — login USULLARI (Auth.js ko'p usulni qo'llab-quvvatlaydi):
// auth.ts
import GitHub from "next-auth/providers/github";
import Google from "next-auth/providers/google";
import Credentials from "next-auth/providers/credentials";
providers: [
// 1. OAUTH (ijtimoiy login — "Google bilan kirish" — parolsiz, oson):
Google({ clientId: process.env.GOOGLE_ID, clientSecret: process.env.GOOGLE_SECRET }),
GitHub,
// 2. CREDENTIALS (email/parol — an'anaviy):
Credentials({
credentials: { email: {}, password: {} },
authorize: async (creds) => {
const user = await db.user.findUnique({ where: { email: creds.email } });
if (user && await bcrypt.compare(creds.password, user.passwordHash)) {
return user; // to'g'ri user; noto'g'ri null
}
return null;
},
}),
],
OAuth (Google/GitHub) — ijtimoiy login (parolsiz, oson, xavfsiz); Credentials — email/parol
Credentials authorize — parolni bcrypt.compare bilan tekshir (HECH QACHON ochiq parol — 2.10)Provayderlar (OAuth, Credentials) — login usullari. Provayder — login usuli; Auth.js ko'p turni qo'llab-quvvatlaydi. Ikki asosij tur: (1) OAuth (ijtimoiy login — Google, GitHub, Facebook):
Google({ clientId, clientSecret })— "Google bilan kirish" tugmasi (foydalanuvchi Google hisobi bilan kiradi — parol eslab qolishi shart emas, Auth.js OAuth oqimini boshqaradi — xavfsiz, oson;clientId/clientSecretGoogle Console'dan olinadi — secret server'da — env). Bu eng oson va xavfsiz usul (parol sizning serveringizda saqlanmaydi — Google boshqaradi); (2) Credentials (email/parol — an'anaviy):Credentials({ authorize })—authorizefunksiya foydalanuvchi kiritgan email/parolni tekshiradi:db.user.findUnique(email bo'yicha topish) +bcrypt.compare(parol, user.passwordHash)(parol hash bilan mos keladimi — 2.10), to'g'ri bo'lsauserqaytaradi (kirdi), noto'g'ri bo'lsanull(rad). Ikki nuqta: (1) OAuth (Google/GitHub) — ijtimoiy login (parolsiz, oson, xavfsiz — parol sizda saqlanmaydi), Credentials — email/parol (an'anaviy, lekin parolni siz saqlaysiz — mas'uliyat); (2) Credentialsauthorizeda parolnibcrypt.comparebilan tekshir (hech qachon ochiq parolni solishtirmang — parol hash qilingan holda saqlanadi — 2.10). Ko'p sayt ikkalasini beradi (Google bilan tez, yoki email/parol). OAuth — foydalanuvchi uchun oson (parol eslab qolish yo'q), Credentials — to'liq nazorat (lekin xavfsizlik mas'uliyati sizda — parol hash, validatsiya). Yangi loyihada OAuth (Google) bilan boshlash tavsiya (oson, xavfsiz); Credentials kerak bo'lsa — bcrypt + ehtiyot. Provayderlar — Auth.js'ning moslashuvchanlik kuchi (ko'p login usuli, bir tizim).
2.4. Sessiya strategiyasi (JWT vs database)
SESSIYA — foydalanuvchi kirgach, "kirgan" holatini SAQLASH (ikki strategiya):
1. JWT (JSON Web Token — default — token cookie'da):
foydalanuvchi ma'lumoti COOKIE'dagi imzolangan token'da (server saqlamaydi)
har so'rovda token tekshiriladi (DB so'rovsiz — tez, kengaytiriladigan)
kamchilik: token'ni darrov bekor qilish qiyin (logout — token muddati tugaguncha)
2. DATABASE SESSION (sessiya DB'da saqlanadi):
sessiya ID cookie'da, ma'lumot DB'da (har so'rovda DB tekshiriladi)
afzallik: sessiyani darrov bekor qilish (DB'dan o'chir — logout darrov)
kamchilik: har so'rovda DB so'rov (sekinroq, lekin nazoratli)
// auth.ts
session: { strategy: "jwt" } // yoki "database" (adapter bilan — 2.7)
┌────────────────────────────────────────────────────────────┐
│ JWT: token cookie'da (tez, DB'siz) | Database: DB'da (nazoratli)│
│ JWT — default, kengaytiriladigan; Database — darrov bekor qilish│
└────────────────────────────────────────────────────────────┘
JWT — token cookie'da (tez, DB so'rovsiz, lekin bekor qilish qiyin); Database — DB'da (nazoratli)
Ko'p loyiha JWT (default — tez); bank/nozik — database (darrov bekor qilish kerak)Sessiya strategiyasi (JWT vs database) — kirgan holatni saqlashning ikki usuli. Foydalanuvchi kirgach (autentifikatsiya), "kirgan" holatini saqlash kerak (har sahifada qayta login so'ramaclik uchun — sessiya). Ikki strategiya: (1) JWT (JSON Web Token — Auth.js default) — foydalanuvchi ma'lumoti cookie'dagi imzolangan token'da saqlanadi (server hech narsa saqlamaydi — "stateless"); har so'rovda token tekshiriladi (imzo to'g'rimi — DB so'rovsiz — tez, ko'p server'da ishlaydi — kengaytiriladigan); kamchilik — token'ni darrov bekor qilish qiyin (logout qilsangiz ham token o'z muddati tugaguncha "haqiqiy" — chunki server saqlamaydi, tekshira olmaydi); (2) Database session — sessiya DB'da saqlanadi (sessiya ID cookie'da, to'liq ma'lumot DB'da); har so'rovda DB tekshiriladi; afzallik — sessiyani darrov bekor qilish (DB'dan o'chirsangiz — logout darrov ishlaydi — masalan "barcha qurilmalardan chiqish"); kamchilik — har so'rovda DB so'rov (sekinroq, lekin nazoratli). Sozlash:
session: { strategy: "jwt" }yoki"database"(adapter bilan — 2.7). Ikki nuqta: (1) JWT — token cookie'da (tez, DB so'rovsiz, kengaytiriladigan, lekin darrov bekor qilish qiyin); Database — DB'da (nazoratli, darrov bekor qilish mumkin, lekin har so'rovda DB); (2) ko'p loyiha JWT (default — tez, sodda); bank/nozik ilova database (sessiyani darrov bekor qilish kerak — xavfsizlik). Tanlov — loyiha ehtiyojiga bog'liq (tezlik vs nazorat). Ko'p holda JWT yetarli (default — Auth.js uni yaxshi boshqaradi). Sessiya — autentifikatsiya bilan login orasidagi "ko'prik" (bir marta kirib, sessiya davomida kirgan qolish).
2.5. Sessiyani olish (server va client)
SESSIYANI OLISH — foydalanuvchi kim (server'da va client'da — har xil):
// SERVER (Server Component, Server Action, Route Handler — auth()):
import { auth } from "@/auth";
export default async function Page() {
const session = await auth(); // server'da sessiya
if (!session) return <p>Kiring</p>;
return <p>Salom, {session.user.name}!</p>;
}
// CLIENT (Client Component — useSession — SessionProvider kerak):
"use client";
import { useSession } from "next-auth/react";
export default function Profile() {
const { data: session, status } = useSession(); // client'da sessiya
if (status === "loading") return <Spinner />;
if (!session) return <p>Kiring</p>;
return <p>Salom, {session.user.name}!</p>;
}
// SessionProvider (client uchun — layout'da):
// <SessionProvider><App /></SessionProvider>
Server: auth() (Server Component/Action/Route — to'g'ridan, tez); Client: useSession (hook)
useSession — SessionProvider kerak (layout'da o'rab); server'da auth() afzal (tezroq, xavfsizroq)Sessiyani olish (server va client) — foydalanuvchi kimligini aniqlash. Sessiyani ikki joyda olish mumkin (har xil usul): (1) server'da (Server Component, Server Action, Route Handler) —
auth()(Auth.js'dan):const session = await auth()— server'da sessiyani to'g'ridan oladi (session.user— foydalanuvchi ma'lumoti;sessionnullbo'lsa — kirmagan). Bu afzal usul (server'da — tezroq, xavfsizroq, qo'shimcha so'rov yo'q); (2) client'da (Client Component) —useSession(next-auth/react'dan):const { data: session, status } = useSession()— client'da sessiyani hook orqali oladi (status—"loading"/"authenticated"/"unauthenticated").useSessionishlashi uchunSessionProviderkerak (layout'da butun ilovani o'rab — Context orqali sessiyani tarqatadi — 12.1). Ikki nuqta: (1) server'daauth()(Server Component/Action/Route — to'g'ridan, tez, xavfsiz); client'dauseSession(hook — interaktiv komponentda); (2)useSession—SessionProviderkerak (layout'da o'rab); server'daauth()afzal (tezroq — server render, xavfsizroq — token brauzerga chiqmaydi). Qachon qaysi: ko'p holda server'daauth()(Server Component'da foydalanuvchini tekshirish — 13.3), client'dauseSessionfaqat interaktiv komponentda kerak bo'lsa (masalan navbar'da "Kirish/Chiqish" tugmasi — foydalanuvchi holatiga qarab). Server-first 13.3-bob — auth'da ham (server'da tekshirish afzal — tezroq, xavfsizroq). Bu — sessiyani har joyda (server, client) olishning usuli.
2.6. Callbacklar (jwt, session)
CALLBACKLAR — token/sessiyaga qo'shimcha ma'lumot qo'shish (rol, ID — sozlash):
// auth.ts — callbacks (token va sessiyani moslash):
callbacks: {
// jwt — token yaratilganda/yangilanganda (rol qo'shish):
async jwt({ token, user }) {
if (user) { // birinchi marta (login paytida)
token.role = user.role; // rolni token'ga qo'sh (DB'dan)
token.id = user.id;
}
return token;
},
// session — sessiya o'qilganda (token'dan sessiyaga):
async session({ session, token }) {
session.user.role = token.role; // rolni sessiyaga (komponentda ishlatish uchun)
session.user.id = token.id;
return session;
},
},
endi session.user.role bor (avtorizatsiya uchun — 2.9):
// const session = await auth();
// if (session.user.role === "admin") { ... }
jwt callback — token'ga ma'lumot (rol, id — DB'dan, login paytida); session — token'dan sessiyaga
Callbacklar — sessiyaga rol/ID qo'shish (avtorizatsiya uchun — default'da faqat name/email)Callbacklar (jwt, session) — token va sessiyani moslashtirish (rol, ID qo'shish). Default'da Auth.js sessiyaga faqat asosiy ma'lumotni (name, email, image) qo'yadi. Lekin avtorizatsiya 2.9-bob uchun rol (admin/foydalanuvchi) va ID kerak — bularni callbacklar orqali qo'shasiz. Ikki asosiy callback: (1)
jwt— token yaratilganda/yangilanganda ishlaydi:async jwt({ token, user }) { if (user) { token.role = user.role; token.id = user.id } return token }— birinchi marta (login paytida —usermavjud — DB'dagi foydalanuvchi), rolni va ID'ni token'ga qo'shadi (keyingi so'rovlarda token'dan o'qiladi — DB'siz); (2)session— sessiya o'qilganda ishlaydi:async session({ session, token }) { session.user.role = token.role; session.user.id = token.id; return session }— token'dagi rolni/ID'ni sessiyaga ko'chiradi (endi komponentdasession.user.rolemavjud). Natija:const session = await auth(); if (session.user.role === "admin") {...}— avtorizatsiya uchun rol mavjud. Ikki nuqta: (1)jwtcallback — token'ga ma'lumot (rol, id — DB'dan, login paytida — bir marta),sessioncallback — token'dan sessiyaga (har o'qishda); (2) callbacklar — sessiyaga rol/ID qo'shish (avtorizatsiya uchun — default faqat name/email beradi). Bu — autentifikatsiya (Auth.js — kim) va avtorizatsiya (rol — nima qila oladi — 2.1)ni bog'laydi (rol sessiyaga qo'shilgach, har joyda ruxsat tekshirsa bo'ladi). Callbacklar — Auth.js'ni o'z ilovangizga moslashtirishning asosiy vositasi (rol, qo'shimcha ma'lumot, maxsus mantiq). Rol-asosli avtorizatsiya uchun callbacklar majburiy (rolni sessiyaga olib chiqish).
2.7. Database adapter (Prisma)
ADAPTER — Auth.js'ni DB bilan bog'lash (foydalanuvchi, sessiya DB'da saqlanadi):
// auth.ts — Prisma adapter (foydalanuvchi/sessiyani DB'da saqla):
import { PrismaAdapter } from "@auth/prisma-adapter";
import { db } from "@/lib/db";
export const { handlers, auth } = NextAuth({
adapter: PrismaAdapter(db), // Auth.js DB'ni boshqaradi (User, Session, Account jadvallari)
providers: [Google],
session: { strategy: "database" }, // adapter bilan database session 2.4-bob
});
ADAPTER NIMA QILADI:
Foydalanuvchi yaratadi (yangi login DB'da User)
OAuth hisoblarini bog'laydi (Account — Google ID User)
Sessiyani DB'da (database strategiya — 2.4)
Auth.js standart sxema (User, Account, Session, VerificationToken)
Adapter — Auth.js'ni DB'ga ulaydi (foydalanuvchi/OAuth hisob/sessiya DB'da — doimiy)
Prisma adapter 6.12-bob — standart sxema; OAuth + database session uchun kerakDatabase adapter (Prisma) — Auth.js'ni ma'lumotlar bazasiga bog'lash. Adapter — Auth.js'ni DB bilan bog'laydi (foydalanuvchi, OAuth hisoblari, sessiya DB'da saqlanishi uchun). Prisma adapter 6.12-bob:
adapter: PrismaAdapter(db)— Auth.js DB'ni boshqaradi (kerakli jadvallarni — User, Account, Session, VerificationToken — ishlatadi). Adapter nima qiladi: (1) foydalanuvchi yaratadi (yangi odam birinchi marta login qilsa — DB'daUseryozyvi yaratiladi — doimiy saqlanadi); (2) OAuth hisoblarini bog'laydi (Accountjadvali — masalan Google ID User — bir foydalanuvchi Google va GitHub bilan ham kirsa, bir hisobga bog'lanadi); (3) sessiyani DB'da saqlaydi (database strategiya — 2.4); (4) Auth.js standart sxemasini (User, Account, Session, VerificationToken jadvallari — Auth.js hujjatida berilgan) ishlatadi. Ikki nuqta: (1) adapter — Auth.js'ni DB'ga ulaydi (foydalanuvchi/OAuth hisob/sessiya DB'da — doimiy saqlanadi — server qayta ishga tushca ham qoladi); (2) Prisma adapter (6.12 — yoki Drizzle, MongoDB adapter) — standart sxema; OAuth + database session uchun kerak (JWT-only, Credentials-only holda adapter shart emas — lekin OAuth uchun foydalanuvchíni DB'da saqlash kerak). Qachon kerak: OAuth (Google/GitHub) ishlatsangiz — adapter (foydalanuvchini DB'da saqlash), yoki database session 2.4-bob. Faqat JWT + Credentials bo'lsa — adapter ixtiyoriy (siz o'z User jadvalingizni boshqarasiz). Adapter — Auth.js'ni sizning DB'ngiz bilan integratsiya qiladi (foydalanuvchi ma'lumotlari doimiy — profil, rol, hisob). Prisma 6.12-bob bilan — eng keng kombinatsiya.
2.8. Kirish va chiqish (signIn, signOut)
KIRISH/CHIQISH — login va logout (server va client'da):
// SERVER (Server Action — forma bilan — progressive enhancement — 13.5):
// auth.ts'dan signIn/signOut
import { signIn, signOut } from "@/auth";
// Kirish formasi (Server Action):
<form action={async () => { "use server"; await signIn("github"); }}>
<button>GitHub bilan kirish</button>
</form>
// Chiqish:
<form action={async () => { "use server"; await signOut(); }}>
<button>Chiqish</button>
</form>
// CLIENT (Client Component — next-auth/react):
"use client";
import { signIn, signOut } from "next-auth/react";
<button onClick={() => signIn("google")}>Google bilan kirish</button>
<button onClick={() => signOut()}>Chiqish</button>
// Credentials (email/parol):
await signIn("credentials", { email, password, redirectTo: "/dashboard" });
signIn(provider) — kirish (OAuth yoki credentials); signOut() — chiqish (server yoki client)
Server (Server Action — forma) yoki client (onClick); redirectTo — kirgach qaergaKirish va chiqish (signIn, signOut) — login va logout amallari.
signIn(kirish) vasignOut(chiqish) — ikki joyda ishlatsa bo'ladi: (1) server'da (Server Action — forma bilan — progressive enhancement — 13.5):auth.ts'dagisignIn/signOutni ishlatish:<form action={async () => { "use server"; await signIn("github") }}>(GitHub bilan kirish — forma submit Server Action OAuth oqimi),<form action={async () => { "use server"; await signOut() }}>(chiqish); (2) client'da (Client Component):next-auth/react'dagisignIn/signOut:<button onClick={() => signIn("google")}>(tugma hodisasi — 13.5: 2.7). Credentials (email/parol):await signIn("credentials", { email, password, redirectTo: "/dashboard" })— provayder nomi"credentials", ma'lumot (email/parol),redirectTo(kirgach qaerga — dashboard).signIn("github")/signIn("google")— OAuth (provayder sahifasiga yo'naltiradi — foydalanuvchi Google/GitHub'da tasdiqlaydi, qaytadi). Ikki nuqta: (1)signIn(provider)— kirish (OAuth provayder yoki credentials),signOut()— chiqish (ikkalasi server yoki client'da); (2) server (Server Action — forma — progressive enhancement, JS'siz ham ishlaydi) yoki client (onClick— interaktiv),redirectTo— kirgach qaerga. Server vs client: server (Server Action) — progressive enhancement (forma JS'siz ham — 13.5: 2.5 — ishonchli), client — darrov interaktiv (loading holati bilan). Ko'p holda server (Server Action — forma) afzal (ishonchli, sodda).signIn/signOut— autentifikatsiya oqimining (kirish/chiqish) amaliy nuqtasi. Auth.js bularni soddalashtiradi (OAuth oqimi, sessiya yaratish — avtomatik).
2.9. Avtorizatsiya — rollar va himoya
AVTORIZATSIYA — rol va ruxsat tekshirish (autentifikatsiyadan keyin — 2.1):
// 1. SAHIFA darajasida (Server Component — rol tekshir):
export default async function AdminPage() {
const session = await auth();
if (!session) redirect("/login"); // kirmagan login
if (session.user.role !== "admin") redirect("/"); // admin emas bosh sahifa
return <AdminPanel />; // faqat admin ko'radi
}
// 2. MIDDLEWARE darajasida (markaziy — 13.6):
// middleware'da rol tekshir /admin'ga faqat admin
// 3. SERVER ACTION/ROUTE darajasida (13.5: 2.11, 13.6: Misol 10):
"use server";
export async function deleteUser(id: string) {
const session = await auth();
if (session?.user.role !== "admin") throw new Error("Ruxsat yo'q"); // tekshir
await db.user.delete({ where: { id } });
}
Avtorizatsiya — har himoyalangan joyda rol tekshir (sahifa + Server Action/Route)
FAQAT sahifada tekshirish YETARLI EMAS — Server Action/API'da HAM (ochiq — 13.5: 2.11)Avtorizatsiya — rollar va himoya — kim nima qila olishini tekshirish (2.1 — authz). Autentifikatsiyadan keyin (kim — login), avtorizatsiya (rol/ruxsat tekshirish) uch joyda: (1) sahifa darajasida (Server Component):
const session = await auth(); if (!session) redirect("/login"); if (session.user.role !== "admin") redirect("/")— kirmagan bo'lsa login'ga, admin emas bo'lsa bosh sahifaga (faqat admin AdminPanel'ni ko'radi — 13.2: Misol 8'ning rol bilan kengaytirilgan versiyasi); (2) middleware darajasida (markaziy — 13.6: Misol 4 —/adminga faqat admin); (3) Server Action/Route darajasida (13.5: 2.11, 13.6: Misol 10):const session = await auth(); if (session?.user.role !== "admin") throw new Error("Ruxsat yo'q")— har mutation/API'da rol tekshir. Eng muhim: faqat sahifada tekshirish yetarli emas — Server Action va Route Handler'da ham tekshirish shart (chunki ular ochiq endpoint — sahifani aylanib o'tib to'g'ridan chaqirsa bo'ladi — 13.5: 2.11, 13.6: 2.6). Masalan: admin sahifani yashirsangiz ham, agardeleteUserServer Action'i rol tekshirmasa — oddiy foydalanuvchi uni to'g'ridan chaqirib, foydalanuvchi o'chira oladi (jiddiy teshik). Ikki nuqta: (1) avtorizatsiya — har himoyalangan joyda rol tekshir (sahifa + Server Action/Route — har qatlam); (2) faqat sahifada tekshirish yetarli emas — Server Action/API'da ham (ochiq — aylanib o'tilishi mumkin — 13.5: 2.11). Bu — chuqur himoya (defense in depth — 14-QISM): har qatlam o'zini himoya qiladi (UI yashirish — UX uchun, lekin haqiqiy himoya har Server Action/API'da). Rol-asosli avtorizatsiya — admin panel, ko'p darajali ruxsat (foydalanuvchi/moderator/admin)ning asosi. Auth.js rolni beradi (callbacklar — 2.6), tekshirish sizning zimmangizda (har joyda).
2.10. Xavfsizlik va best practices
AUTENTIFIKATSIYA XAVFSIZLIGI (eng nozik soha — ehtiyot):
PAROL HASH — hech qachon ochiq parol saqlama (bcrypt/argon2):
const hash = await bcrypt.hash(password, 10); // ro'yxatda (hash saqlanadi)
await bcrypt.compare(password, hash); // kirishda (solishtirish)
SECRET — AUTH_SECRET (token imzosi — kuchli, env'da):
// .env: AUTH_SECRET=<uzun tasodifiy satr> (npx auth secret bilan generatsiya)
HTTPS — production'da majburiy (cookie/token shifrlangan kanal)
CSRF — Auth.js avtomatik (token bilan — siz o'ylamaysiz)
Avtorizatsiya har qatlamda (sahifa + Server Action/API — 2.9)
Sessiya muddati (maxAge — token cheksiz emas)
BEST PRACTICES:
OAuth (Google/GitHub) afzal (parol siz saqlamaysiz — xavfsizroq)
Credentials bcrypt + validatsiya (Zod)
Rol callbacks orqali 2.6-bob; tekshir har joyda 2.9-bob
Secret env'da (hech qachon kodda); HTTPS production
Parol HASH (bcrypt — ochiq emas); AUTH_SECRET kuchli; HTTPS; CSRF avtomatik (Auth.js)
Best: OAuth afzal, bcrypt, rol tekshir har qatlamda, secret env, sessiya muddatiXavfsizlik va best practices — autentifikatsiyaning eng nozik tomoni. Xavfsizlik (autentifikatsiya — eng nozik soha — xato qilsangiz ma'lumot o'g'irlanadi): (1) parol hash — hech qachon ochiq (plain) parolni saqlamang — bcrypt (yoki argon2) bilan hash:
bcrypt.hash(password, 10)(ro'yxatda — hash saqlanadi, ochiq parol hech qaerda yo'q),bcrypt.compare(password, hash)(kirishda — solishtirish — 2.3). Agar ochiq parol saqlasangiz va DB sizib ketsa — barcha foydalanuvchi paroli ochiq (falokat); hash bilan — parollar himoyalangan; (2) secret —AUTH_SECRET(token imzosi uchun — kuchli, tasodifiy —npx auth secretbilan generatsiya, env'da — hech qachon kodda); (3) HTTPS — production'da majburiy (cookie/token shifrlangan kanalda — aks holda o'g'irlanadi); (4) CSRF — Auth.js avtomatik himoya qiladi (token bilan — siz o'ylamaysiz); (5) avtorizatsiya har qatlamda (sahifa + Server Action/API — 2.9); (6) sessiya muddati (maxAge— token cheksiz emas — vaqti-vaqti qayta login). Best practices: OAuth (Google/GitHub) afzal (parol siz saqlamaysiz — Google boshqaradi — xavfsizroq); Credentials bcrypt + validatsiya (Zod — 13.5: 2.9); rol callbacks orqali 2.6-bob, tekshir har joyda 2.9-bob; secret env'da, HTTPS production. Ikki nuqta: (1) parol hash (bcrypt — ochiq emas),AUTH_SECRETkuchli, HTTPS, CSRF avtomatik (Auth.js — bularning ko'rini hal qiladi); (2) best: OAuth afzal, bcrypt, rol tekshir har qatlamda, secret env, sessiya muddati. Bu — 14-QISM (Xavfsizlik)da chuqurroq ochiladi — bu yerda autentifikatsiya xavfsizligining asoslari ko'rsatildi. Auth.js ko'p xavfsizlik ishini (CSRF, token, sessiya) qiladi, lekin parol hash, secret, avtorizatsiya tekshir — sizning zimmangizda. Autentifikatsiya — o'zingiz noldan yozishdan (xavfli) kutubxona (Auth.js) afzal, lekin baribir ehtiyot (xavfsizlik — doimiy mas'uliyat).
2.11. Boshqa provayderlar (Email magic link, WebAuthn/passkey, Discord)
OAuth VA CREDENTIALS'DAN TASHQARI PROVAYDERLAR:
// 1. EMAIL (magic link — parolsiz — email'ga havola yuboriladi):
import Resend from "next-auth/providers/resend"; // yoki Nodemailer
providers: [
Resend({ from: "no-reply@sayt.com" }), // sozlash: SMTP/API kaliti
]
foydalanuvchi email kiritadi email'ga "sehrli havola" bosadi kirdi
parol YO'Q; VerificationToken jadvali kerak (adapter — 2.7)
// 2. WebAuthn / PASSKEY (barmoq izi, Face ID, xavfsizlik kaliti — parolsiz):
import Passkey from "next-auth/providers/passkey";
experimental: { enableWebAuthn: true }, // v5 experimental
providers: [ Passkey ]
qurilma (barmoq/yuz) bilan kirish — eng xavfsiz (fishing'ga chidamli)
// 3. DISCORD (yana bir OAuth — o'yin/hamjamiyat ilovalari):
import Discord from "next-auth/providers/discord";
Discord({ clientId: process.env.DISCORD_ID!, clientSecret: process.env.DISCORD_SECRET! })
Email — magic link (parolsiz, email tasdiq); WebAuthn — passkey (qurilma, eng xavfsiz)
Discord/Google/GitHub — bir xil OAuth naqsh (clientId/secret + callback URL)Boshqa provayderlar (Email magic link, WebAuthn/passkey, Discord) — OAuth va Credentials'dan tashqari yana uch muhim usul. (1) Email (magic link) — parolsiz autentifikatsiya: foydalanuvchi faqat email kiritadi, unga "sehrli havola" (magic link) yuboriladi, havolani bossa — kirdi (parol umuman yo'q — "email'im borligini isbotladim" degani).
ResendyokiNodemailerprovayderi (Resend({ from })— jo'natuvchi manzil; API kaliti/SMTP env'da). Bu usulVerificationTokenjadvalini talab qiladi (adapter — 2.7 — havola tokeni DB'da saqlanadi, bir marta ishlatiladi). Afzalligi — parol yo'q (unutilmaydi, o'g'irlanmaydi), kamchiligi — har kirishda email kutish; (2) WebAuthn / passkey — qurilma xavfsizligi bilan kirish (barmoq izi, Face ID, yoki jismoniy xavfsizlik kaliti).Passkeyprovayderi (v5'daexperimental: { enableWebAuthn: true }bilan). Bu eng xavfsiz usul — fishing (soxta sayt orqali o'g'irlash)ga chidamli (kalit qurilmadan chiqmaydi), parol umuman yo'q; (3) Discord — yana bir OAuth provayder (o'yin, hamjamiyat ilovalarida keng — Google/GitHub bilan bir xil naqsh:clientId/clientSecret+ callback URL). Auth.js 80+ tayyor OAuth provayderni qo'llab-quvvatlaydi (Google, GitHub, Discord, Facebook, Apple, Twitter va h.k. — hammasi bir xilProvider({ clientId, clientSecret })naqshi). Ikki nuqta: (1) Email — magic link (parolsiz, email orqali tasdiq —VerificationTokenjadvali kerak), WebAuthn — passkey (qurilma bilan — parolsiz, eng xavfsiz); (2) Discord/Google/GitHub va boshqa OAuth — bir xil naqsh (clientId/clientSecret+ provayder console'da callback URL sozlash). Provayder tanlovi UX va xavfsizlikka bog'liq: OAuth (tez), magic link (parolsiz, sodda), passkey (eng xavfsiz — zamonaviy tavsiya), Credentials (to'liq nazorat). Ko'p sayt bir nechtasini birga beradi (foydalanuvchi tanlaydi).
2.12. DB sxema, environment o'zgaruvchilar va token refresh
AUTH.JS STANDART DB SXEMA (adapter uchun — Prisma misolida):
model User { id, name, email, emailVerified, image, role, accounts, sessions }
model Account { userId, provider, providerAccountId, access_token, refresh_token, ... }
model Session { sessionToken, userId, expires } // database strategiyada
model VerificationToken { identifier, token, expires } // magic link uchun
ENVIRONMENT O'ZGARUVCHILAR (.env — hech qachon git'ga):
AUTH_SECRET=<npx auth secret> # token imzosi (majburiy)
AUTH_URL=https://sayt.com # production URL (callback uchun)
GOOGLE_ID=... / GOOGLE_SECRET=... # OAuth kalitlari
GITHUB_ID=... / GITHUB_SECRET=...
DATABASE_URL=postgresql://... # adapter DB 6.12-bob
TOKEN REFRESH (OAuth access_token muddati tugasa — refresh_token bilan yangilash):
callbacks: { async jwt({ token, account }) {
if (account) token.refresh_token = account.refresh_token; // login'da saqla
// muddat tugasa provayder token endpoint'iga refresh_token yangi access_token
}}
Account jadvali OAuth token (access/refresh)ni saqlaydi; VerificationToken — magic link
AUTH_SECRET/AUTH_URL/OAuth kalitlari env'da; refresh_token bilan access_token yangilanadiDB sxema, environment o'zgaruvchilar va token refresh — adapter ishlashi uchun kerakli poydevor. (1) Auth.js standart DB sxemasi — adapter 2.7-bob to'rt asosiy jadval bilan ishlaydi:
User(foydalanuvchi — id, ism, email,emailVerified, rasm, va siz qo'shganrole);Account(OAuth hisoblari — bir User bir nechta provayder bilan bog'lanishi mumkin;provider,providerAccountId, hamda OAuthaccess_token/refresh_tokenshu yerda saqlanadi);Session(database strategiyada —sessionToken,userId,expires);VerificationToken(magic link/email tasdiq tokenlari — 2.11). Bu sxemani Auth.js hujjati aynan beradi (Prisma/Drizzle uchun tayyorschema.prisma— nusxa olibprisma migrate— 6.12); (2) Environment o'zgaruvchilar — nozik ma'lumotlar.envfaylda (hech qachon git'ga qo'yilmaydi —.gitignore):AUTH_SECRET(token imzosi — majburiy),AUTH_URL(production URL — callback uchun), OAuth kalitlari (GOOGLE_ID/GOOGLE_SECRETva h.k. — provayder console'dan),DATABASE_URL(adapter DB ulanishi). Auth.js v5 ba'zi o'zgaruvchilarni avtomatik taniydi (masalanAUTH_GOOGLE_ID/AUTH_GOOGLE_SECRETprefiksi bilan — qo'ldaclientIdberish shart emas); (3) Token refresh — OAuthaccess_tokencheksiz emas (masalan Google — 1 soat). Muddati tugagach, provayderga saqlanganrefresh_tokenyuborilib yangiaccess_tokenolinadi (agar provayder API'siga so'rov qilib turish kerak bo'lsa — masalan Google Calendar o'qish). Bunijwtcallback'da amalga oshiriladi (login'daaccount.refresh_tokenni saqlab, muddat tekshiruvi bilan yangilash). Oddiy auth (faqat "kim kirgan") uchun refresh kerak emas — u faqat tashqi API'ga uzluksiz kirish kerak bo'lganda muhim. Ikki nuqta: (1)Accountjadvali OAuth tokenlarini (access/refresh) saqlaydi,VerificationToken— magic link,Session— database strategiya; (2)AUTH_SECRET/AUTH_URL/OAuth kalitlari env'da (git'siz), refresh_token bilan access_token muddati tugagach yangilanadi. Bu sxema va env sozlamalar — Auth.js'ni real DB va provayderlar bilan ishlashga tayyorlaydi (production poydevori).
2.13. Next.js auth vs alohida backend auth (NestJS JWT — 08-QISM)
IKKI YONDASHUV — auth QAERDA (Next.js'da yoki alohida backend'da):
A. NEXT.JS AUTH (Auth.js — bu bob):
Next.js o'zi auth qiladi (fullstack — frontend + auth bir loyihada)
mos: Next.js — asosiy backend (Server Actions/Route Handlers — DB'ga to'g'ridan)
B. ALOHIDA BACKEND AUTH (08-QISM NestJS JWT):
backend (NestJS) JWT beradi; Next.js token'ni saqlab, so'rovlarda yuboradi
mos: alohida backend bor (mobil + web bir API'ni ulashadi); mikroservis
INTEGRATSIYA (B holatda):
NestJS login JWT Next.js httpOnly cookie'da saqlaydi (yoki Auth.js Credentials
provayderi NestJS'ga so'rov qilib, qaytgan tokenni sessiyaga qo'yadi)
Next.js asosiy backend Auth.js (bu bob); alohida NestJS API backend JWT (08-QISM)
Ikkalasini birlashtirish: Auth.js Credentials NestJS'ga so'rov token sessiyagaNext.js auth vs alohida backend auth (NestJS JWT — 08-QISM) — auth qaerda bo'lishi kerak degan me'moriy savol. Ikki yondashuv: (A) Next.js auth (Auth.js — bu bob) — Next.js o'zi autentifikatsiyani qiladi (fullstack — frontend, auth va API bir loyihada). Bu Next.js asosiy backend bo'lganda mos (Server Actions/Route Handlers to'g'ridan DB bilan ishlaydi — 13.5, 6.12); (B) Alohida backend auth (08-QISM — NestJS JWT) — backend (NestJS) autentifikatsiyani qiladi va JWT beradi, Next.js esa faqat token'ni saqlab, backend so'rovlariga yuboradi. Bu alohida backend bo'lganda mos (masalan bir NestJS API'ni ham web (Next.js), ham mobil ilova ulashadi — auth bir joyda, backend'da; yoki mikroservis arxitektura). Qachon qaysi: agar Next.js loyihaning yagona backend'i bo'lsa — Auth.js (sodda, integratsiyalangan); agar allaqachon alohida API (NestJS/Express) bo'lsa yoki ko'p mijoz (web + mobil) bir API'ni ulashsa — backend auth (08-QISM JWT — markaziy). Integratsiya (ikkalasini birlashtirish): Next.js Auth.js'ning Credentials provayderi ichidan NestJS backend'ining login endpoint'iga so'rov qilib (email/parol NestJS tekshiradi JWT qaytaradi), qaytgan tokenni Auth.js sessiyasiga (
jwtcallback — 2.6) joylash mumkin. Yoki NestJS bergan JWT'ni Next.jshttpOnlycookie'da saqlab (10.11 — cookie xavfsizligi), har backend so'rovigaAuthorizationheader'da yuborish. Ikki nuqta: (1) Next.js asosiy backend bo'lsa — Auth.js (bu bob); alohida NestJS/Express API bo'lsa — backend JWT (08-QISM); (2) ikkalasini birlashtirish mumkin (Auth.js Credentials NestJS'ga so'rov tokenni sessiyaga). Tanlov loyiha arxitekturasiga bog'liq (monolit fullstack Next.js vs alohida API + ko'p mijoz). Bu — 08-QISM (NestJS backend auth) va 13-QISM (Next.js auth)ni bog'laydigan me'moriy qaror.
2.14. Muqobil yechimlar (Clerk, Lucia, Supabase Auth)
AUTH.JS'DAN TASHQARI (qisqacha — muqobillar):
CLERK to'liq boshqariladigan auth (tayyor UI komponentlar, foydalanuvchi
paneli, org/team — pullik SaaS; eng kam kod, tez ishga tushirish)
LUCIA yengil, kutubxona emas "resept" (to'liq nazorat, o'z sxemang;
past darajali — ko'proq kod, lekin sehr yo'q, tushunarli)
SUPABASE Supabase backend bilan (Postgres + auth + storage bir platformada;
RLS — row level security bilan integratsiya)
Auth.js — Next.js standarti (bepul, moslashuvchan); Clerk — tez/pullik; Lucia — past daraja
Tanlov: tez ishga tushirish Clerk; to'liq nazorat Lucia; Supabase stack Supabase AuthMuqobil yechimlar (Clerk, Lucia, Supabase Auth) — Auth.js yagona variant emas; qisqacha muqobillar. (1) Clerk — to'liq boshqariladigan (managed) autentifikatsiya xizmati: tayyor UI komponentlar (
<SignIn />,<UserButton />), foydalanuvchi boshqaruv paneli, tashkilot/jamoa (org/team), MFA — hammasi tayyor. Eng kam kod bilan tez ishga tushadi, lekin pullik SaaS (foydalanuvchi soniga qarab) va tashqi xizmatga bog'liqlik; (2) Lucia — yengil, "kutubxona emas, reseptlar to'plami" yondashuvi: sessiya boshqaruvini o'zingiz DB sxemangiz bilan quolasiz (to'liq nazorat, "sehr" yo'q — nima bo'layotgani ochiq). Past darajali — ko'proq kod, lekin har qadamni tushunasiz (o'rganish uchun ham yaxshi); (3) Supabase Auth — Supabase platformasi (Postgres + auth + storage + realtime) bilan integratsiyalangan auth. Agar backend sifatida Supabase ishlatsangiz mantiqiy tanlov (auth Postgres RLS — row level security bilan bevosita bog'lanadi). Ikki nuqta: (1) Auth.js — Next.js'ning de-fakto standarti (bepul, ochiq, moslashuvchan — ko'p loyiha uchun to'g'ri tanlov); Clerk — tez, lekin pullik/managed; Lucia — past daraja, to'liq nazorat; (2) tanlov ehtiyojga bog'liq: eng tez ishga tushirish va tayyor UI Clerk; to'liq nazorat va o'rganish Lucia; Supabase stack'da bo'lsangiz Supabase Auth; standart, bepul, Next.js bilan chuqur integratsiya Auth.js (bu bob). Bu bob Auth.js'ga qaratilgan (Next.js ekotizimidagi eng keng tarqalgan tanlov), lekin muqobillarni bilish — loyihaga to'g'ri vositani tanlashda foydali (universal g'oyalar — session, provayder, RBAC — barchasida bir xil).
3. Sintaksis — tez ma'lumotnoma
SOZLASH 2.2-bob: auth.ts NextAuth({ providers, callbacks, session })
ENDPOINT 2.2-bob: app/api/auth/[...nextauth]/route.ts export const { GET, POST } = handlers
PROVAYDER 2.3-bob: Google({ clientId, clientSecret }) | Credentials({ authorize })
SESSIYA 2.4-bob: session: { strategy: "jwt" | "database" }
OLISH SERVER 2.5-bob:const session = await auth()
OLISH CLIENT 2.5-bob:const { data: session } = useSession() (SessionProvider kerak)
CALLBACK 2.6-bob: callbacks: { jwt({token,user}), session({session,token}) }
ADAPTER 2.7-bob: adapter: PrismaAdapter(db)
KIRISH 2.8-bob: signIn("google") | signIn("credentials", {...}) | signOut()
ROL 2.9-bob: if (session.user.role !== "admin") redirect("/")
PAROL 2.10-bob: bcrypt.hash(pw, 10) | bcrypt.compare(pw, hash)4. Batafsil kod namunalari
Har misol: Maqsad + izohli kod + "Bu kod nima qiladi".
Misol 1 — Auth.js asosiy sozlash (OAuth — 2.2, 2.3)
Maqsad: Auth.js'ni Google/GitHub login bilan sozlash — eng oson, eng xavfsiz boshlanish. Bu har Next.js auth loyihasining poydevori.
// auth.ts — markaziy sozlama (loyiha ildizida)
import NextAuth from "next-auth";
import Google from "next-auth/providers/google";
import GitHub from "next-auth/providers/github";
import { PrismaAdapter } from "@auth/prisma-adapter";
import { db } from "@/lib/db";
export const { handlers, auth, signIn, signOut } = NextAuth({
adapter: PrismaAdapter(db), // foydalanuvchini DB'da saqla (2.7)
providers: [
Google({ clientId: process.env.GOOGLE_ID!, clientSecret: process.env.GOOGLE_SECRET! }),
GitHub({ clientId: process.env.GITHUB_ID!, clientSecret: process.env.GITHUB_SECRET! }),
],
session: { strategy: "jwt" }, // JWT sessiya (2.4)
pages: { signIn: "/login" }, // maxsus login sahifasi (default emas)
});
// app/api/auth/[...nextauth]/route.ts — Auth.js endpoint:
// import { handlers } from "@/auth";
// export const { GET, POST } = handlers;Bu kod nima qiladi: Bu — Auth.js'ning asosiy sozlamasi (OAuth login bilan — 2.2, 2.3). auth.ts (markaziy fayl) NextAuth({...}) chaqiradi va to'rt narsani export qiladi: handlers (auth endpoint), auth (sessiyani olish — 2.5), signIn/signOut (kirish/chiqish — 2.8). Sozlamalar: (1) adapter: PrismaAdapter(db) — foydalanuvchilarni DB'da saqlaydi (2.7 — yangi login DB'da User; OAuth hisoblari bog'lanadi); (2) providers — ikki OAuth: Google va GitHub (har biri clientId/clientSecret — provayder console'dan olingan, env'da — secret server'da — 2.3); (3) session: { strategy: "jwt" } — JWT sessiya (token cookie'da — tez — 2.4); (4) pages: { signIn: "/login" } — maxsus login sahifasi (Auth.js default sahifasi o'rniga o'z dizayningiz). Va app/api/auth/[...nextauth]/route.tsda handlersni export qilinadi (Auth.js o'z route'ini — OAuth oqimi, callback — boshqaradi — 2.2). Endi ilovangizda autentifikatsiya tayyor: foydalanuvchi "Google bilan kirish" bossa — Google'ga yo'naltiriladi, tasdiqlab qaytadi, Auth.js sessiya yaratadi (DB'da User, JWT token), va u kirgan hisoblanadi. Bu — minimal, lekin to'liq ishlaydigan auth sozlamasi (OAuth — eng oson, eng xavfsiz — parol siz saqlamaysiz, Google boshqaradi). Real loyiha shundan boshlaydi (Google/GitHub login — bir necha qator bilan to'liq autentifikatsiya). Auth.js murakkab ishni (OAuth oqimi, sessiya, CSRF) yashiradi — siz sozlamani berasiz.
Misol 2 — Credentials (email/parol — 2.3, 2.10)
Maqsad: Email/parol bilan login qilish — bcrypt parol tekshiruvi bilan. Bu an'anaviy login uchun, xavfsizlik (hash) bilan.
// auth.ts — Credentials provayder
import Credentials from "next-auth/providers/credentials";
import bcrypt from "bcryptjs";
import { z } from "zod";
const LoginSchema = z.object({
email: z.string().email(),
password: z.string().min(6),
});
export const { handlers, auth, signIn, signOut } = NextAuth({
providers: [
Credentials({
authorize: async (credentials) => {
// 1. Validatsiya (Zod — kirish ma'lumotini tekshir):
const parsed = LoginSchema.safeParse(credentials);
if (!parsed.success) return null; // noto'g'ri format rad
// 2. Foydalanuvchini topish:
const user = await db.user.findUnique({ where: { email: parsed.data.email } });
if (!user || !user.passwordHash) return null; // yo'q rad
// 3. Parolni tekshir (bcrypt — hash bilan — 2.10):
const valid = await bcrypt.compare(parsed.data.password, user.passwordHash);
if (!valid) return null; // noto'g'ri parol rad
return { id: user.id, email: user.email, name: user.name, role: user.role }; // kirdi
},
}),
],
session: { strategy: "jwt" },
});Bu kod nima qiladi: Bu — email/parol bilan login (Credentials — an'anaviy, xavfsizlik bilan — 2.3, 2.10). Credentials provayderining authorize funksiyasi foydalanuvchi kiritgan email/parolni tekshiradi (uch qadam): (1) validatsiya — Zod bilan (LoginSchema.safeParse — email to'g'ri formatda'mi, parol kamida 6 belgimi — 13.5: 2.9); noto'g'ri bo'lsa null (rad); (2) foydalanuvchini topish — db.user.findUnique (email bo'yicha); topilmasa yoki paroli yo'q (OAuth bilan ro'yxatdan o'tgan — paroli yo'q) bo'lsa null (rad); (3) parolni tekshir — bcrypt.compare(kiritilgan parol, user.passwordHash) (2.10 — foydalanuvchi kiritgan parolni DB'dagi hash bilan solishtiradi — bcrypt hash'ni teskari ocha olmaydi, lekin solishtira oladi); noto'g'ri bo'lsa null (rad); to'g'ri bo'lsa foydalanuvchi ma'lumotini (id, email, name, role — rol callbacks uchun — 2.6) qaytaradi (kirdi). Eng muhim xavfsizlik: parol DB'da hash holda saqlanadi (ochiq emas — 2.10) — authorizeda bcrypt.compare bilan solishtiriladi (kiritgan parolni hash qilib, saqlangan hash bilan taqqoslaydi). Agar ochiq parol solishtirsangiz (if (password === user.password)) — bu xavfli (DB sizsa barcha parol ochiq). authorize null qaytarsa — Auth.js login'ni rad etadi (foydalanuvchiga "noto'g'ri email yoki parol"). Bu — an'anaviy email/parol login'ning xavfsiz amali (validatsiya + foydalanuvchi topish + bcrypt). Ro'yxatda (Misol kerak bo'lsa) parol bcrypt.hash(password, 10) bilan hash qilib saqlanadi. Credentials — to'liq nazorat, lekin xavfsizlik mas'uliyati sizda (OAuth'da Google boshqaradi — Misol 1 — osonroq).
Misol 3 — Sessiyani server'da olish (himoyalangan sahifa — 2.5, 2.9)
Maqsad: Himoyalangan sahifani server'da sessiya bilan himoyalash — kirmagan foydalanuvíni login'ga. Bu eng keng auth naqshi (13.2: Misol 8'ning to'liq versiyasi).
// app/dashboard/page.tsx — himoyalangan (Server Component)
import { auth } from "@/auth";
import { redirect } from "next/navigation";
export default async function DashboardPage() {
const session = await auth(); // server'da sessiya (2.5)
// Kirmagan login'ga (server'da — xavfsiz, tez — 13.2: Misol 8):
if (!session) {
redirect("/login");
}
// Bu yerga faqat KIRGAN foydalanuvchi yetadi:
return (
<main>
<h1>Dashboard</h1>
<p>Salom, {session.user.name}!</p>
<p>Email: {session.user.email}</p>
{/* Rolga qarab (avtorizatsiya — 2.9): */}
{session.user.role === "admin" && <AdminLink />}
</main>
);
}Bu kod nima qiladi: Bu — himoyalangan sahifa (server'da sessiya bilan — eng keng auth naqshi — 2.5, 2.9). DashboardPage (Server Component) server'da render bo'lishidan oldin sessiyani tekshiradi: const session = await auth() (2.5 — server'da sessiya — session.user mavjud bo'lsa kirgan, null bo'lsa kirmagan). Agar !session (kirmagan) — redirect("/login") (server'da login'ga yo'naltiradi — komponent render to'xtaydi — himoyalangan kontent brauzerga umuman yuborilmaydi — 13.2: Misol 8). Agar sessiya bor — sahifa davom etadi, foydalanuvchi ma'lumotini ko'rsatadi (session.user.name, email), va rolga qarab qo'shimcha (session.user.role === "admin" && <AdminLink /> — admin uchun qo'shimcha havola — avtorizatsiya — 2.9). Nega server'da (Client guard o'rniga — 11.15): (1) xavfsiz — himoyalangan kontent brauzerga umuman yuborilmaydi (Client guard'da kontent yuboriladi, keyin yashiriladi — texnik jihatdan ko'riladi — 13.2: Misol 8); (2) tez — server darrov yo'naltiradi (JavaScript yuklanishini kutmacdan). Bu — Next.js'ning eng keng auth naqshi: har himoyalangan sahifa boshida const session = await auth(); if (!session) redirect("/login"). Rolga qarab (admin) — avtorizatsiya (2.9 — rol sessiyaga callbacks orqali qo'shilgan — 2.6). Eslatma: bu faqat UI himoyasi — agar sahifada Server Action bo'lsa, u ham alohida tekshirilishi shart (2.9, Misol 5 — ochiq endpoint). Server-first auth (13.3 falsafasi auth'da) — server'da tekshirish, xavfsiz, tez. Bu naqsh har himoyalangan sahifada takrorlanadi (dashboard, profil, sozlamalar).
Misol 4 — Middleware bilan himoya (markaziy — 2.9, 13.6)
Maqsad: Barcha himoyalangan yo'llarni markaziy himoyalash — Auth.js middleware bilan. Bu har sahifada guard yozishdan qutqaradi (13.6: Misol 4'ning Auth.js versiyasi).
// middleware.ts — Auth.js bilan markaziy himoya
import { auth } from "@/auth";
export default auth((req) => {
const { pathname } = req.nextUrl;
const isLoggedIn = !!req.auth; // Auth.js sessiyani req.auth'ga qo'shadi
const role = req.auth?.user?.role;
// 1. Himoyalangan yo'l + kirmagan login:
if (pathname.startsWith("/dashboard") && !isLoggedIn) {
return Response.redirect(new URL("/login", req.url));
}
// 2. Admin yo'l + admin emas bosh sahifa (avtorizatsiya — 2.9):
if (pathname.startsWith("/admin") && role !== "admin") {
return Response.redirect(new URL("/", req.url));
}
});
// Qaysi yo'llapga (matcher — 13.6: 2.8):
export const config = {
matcher: ["/dashboard/:path*", "/admin/:path*"],
};Bu kod nima qiladi: Bu — markaziy auth himoyasi (Auth.js middleware — 13.6: Misol 4'ning Auth.js bilan to'liq versiyasi). Auth.js auth funksiyasini middleware sifatida ishlatadi: export default auth((req) => {...}) — Auth.js sessiyani avtomatik req.authga qo'shadi (!!req.auth — kirgan'mi, req.auth?.user?.role — rol). Ikki qoida: (1) himoyalangan yo'l + kirmagan — /dashboardga kirmagan odam kelsa, login'ga yo'naltiradi (autentifikatsiya); (2) admin yo'l + admin emas — /adminga admin bo'lmagan foydalanuvchi (hatto kirgan, lekin oddiy) kelsa, bosh sahifaga yo'naltiradi (avtorizatsiya — rol tekshir — 2.9). matcher (["/dashboard/:path*", "/admin/:path*"]) — middleware faqat shu yo'llarga ishlaydi (13.6: 2.8 — performance). Nega middleware (har sahifada guard o'rniga — Misol 3): markaziy — bir joyda butun himoya (har /dashboard/* va /admin/* sahifaga alohida guard yozish shart emas), va tezroq (edge'da — sahifa render bo'lishidan oldin — 13.6: 2.9). Auth.js middleware integratsiyasi (auth((req) => ...)) buni juda soddalashtiradi (req.auth — sessiya avtomatik — qo'lda cookie o'qish yo'q — 13.6: Misol 4'dagi qo'lda token o'qishdan farqli). Demak: middleware (markaziy — /dashboard, /admin — Misol 4) + Server Component tekshiruvi (Misol 3 — qo'shimcha qatlam) + Server Action/API tekshiruvi (Misol 5 — ochiq endpoint) = chuqur himoya (defense in depth — 2.9). Middleware — birinchi himoya qatlami (markaziy, tez), lekin yagona emas (har Server Action/API ham o'zini himoya qiladi). Bu — Auth.js + Next.js middleware integratsiyasining kuchi (markaziy auth — kam kod, yuqori himoya).
Misol 5 — Server Action avtorizatsiya (rol — 2.9)
Maqsad: Server Action'ni avtorizatsiya bilan himoyalash — faqat admin foydalanuvchi bajara olishi. Bu UI himoyasidan ham muhim (ochiq endpoint — 13.5: 2.11).
// app/admin/actions.ts — admin Server Actionlari
"use server";
import { auth } from "@/auth";
import { revalidatePath } from "next/cache";
// Yordamchi — admin tekshiruvi (qayta ishlatiladi):
async function requireAdmin() {
const session = await auth();
if (!session) throw new Error("Tizimga kiring");
if (session.user.role !== "admin") throw new Error("Faqat admin uchun"); // rol
return session;
}
export async function deleteUser(userId: string) {
await requireAdmin(); // HAR Server Action'da tekshir (ochiq endpoint — 13.5: 2.11)
await db.user.delete({ where: { id: userId } });
revalidatePath("/admin/users");
}
export async function banUser(userId: string) {
await requireAdmin(); // takror tekshir (har action mustaqil himoyalangan)
await db.user.update({ where: { id: userId }, data: { banned: true } });
revalidatePath("/admin/users");
}Bu kod nima qiladi: Bu — Server Action avtorizatsiyasi (rol bilan — UI himoyasidan ham muhim — 2.9, 13.5: 2.11). requireAdmin yordamchi funksiya: const session = await auth(); if (!session) throw...; if (session.user.role !== "admin") throw... — ikki tekshiruv (autentifikatsiya — kirgan'mi; avtorizatsiya — admin'mi), tekshiryvdan o'tsa sessiyani qaytaradi (qayta ishlatiladigan — DRY — har admin action'da takrorlamacdan). Har admin Server Action (deleteUser, banUser) birinchi qadam — await requireAdmin() (tekshirish, keyin amal). Nega bu UI himoyasidan ham muhim (Misol 3 — sahifa admin'ni yashiradi): Server Action ochiq endpoint (13.5: 2.11) — agar admin sahifani yashirsangiz ham (UI), deleteUser Server Action'i rol tekshirmasa, oddiy foydalanuvchi uni to'g'ridan chaqirib (brauzer devtools, yoki HTTP so'rov), foydalanuvchi o'chira oladi (jiddiy xavfsizlik teshigi). UI yashirish — faqat ko'rinish (oddiy foydalanuvchí "O'chirish" tugmasini ko'rmaydi), lekin haqiqiy himoya — Server Action'da (kim chaqirsa ham, rol tekshiriladi). Har action mustaqil himoyalangan (requireAdmin har birida — biri ikkinchisiga ishonmaydi). Bu — chuqur himoya (defense in depth — 2.9, 14-QISM): UI (Misol 3) + middleware (Misol 4) + Server Action (bu Misol) — har qatlam o'zini himoya qiladi (biror qatlam aylanib o'tilsa — keyingi qatlam ushlaydi). Eng keng xato — faqat UI yoki middleware'da tekshirib, Server Action'ni himoyalamaslik (ochiq qoldirish — har kim chaqira oladi). To'g'ri: har himoyalangan Server Action o'z avtorizatsiya tekshiruvi bilan. Bu — xavfsiz mutation'ning asosi (server'da bo'lgani yetarli emas — kim chaqirayotganini tekshir).
Misol 6 — Client'da sessiya (navbar — 2.5)
Maqsad: Navbar'da foydalanuvchi holatiga qarab UI ko'rsatish (kirgan/kirmagan) — useSession bilan. Bu interaktiv komponentda client sessiyasi kerak bo'lgan holat.
// app/components/Navbar.tsx — Client (foydalanuvchi holatiga qarab)
"use client";
import { useSession, signIn, signOut } from "next-auth/react";
import Link from "next/link";
export default function Navbar() {
const { data: session, status } = useSession(); // client'da sessiya (2.5)
return (
<nav>
<Link href="/">Bosh</Link>
{status === "loading" ? (
<span>...</span> // sessiya yuklanmoqda
) : session ? (
// KIRGAN — profil + chiqish:
<>
<span>Salom, {session.user?.name}</span>
<Link href="/dashboard">Dashboard</Link>
<button onClick={() => signOut()}>Chiqish</button>
</>
) : (
// KIRMAGAN — kirish:
<button onClick={() => signIn()}>Kirish</button>
)}
</nav>
);
}
// app/layout.tsx — SessionProvider (useSession uchun — 2.5):
// import { SessionProvider } from "next-auth/react";
// <SessionProvider><Navbar />{children}</SessionProvider>Bu kod nima qiladi: Bu — client'da sessiya (navbar — interaktiv komponentda — 2.5). Navbar — Client Component ("use client" — foydalanuvchi holatiga qarab interaktiv o'zgaradi). useSession() — client'da sessiyani oladi: data: session (foydalanuvchi ma'lumoti yoki null), status ("loading"/"authenticated"/"unauthenticated"). Navbar uch holatda: (1) status === "loading" — sessiya hali yuklanmoqda (... — bir lahzali); (2) session bor (kirgan) — foydalanuvchi nomi, dashboard havolasi, "Chiqish" tugmasi (signOut()); (3) session yo'q (kirmagan) — "Kirish" tugmasi (signIn()). useSession ishlashi uchun SessionProvider kerak (layout'da butun ilovani o'rab — Context orqali sessiyani tarqatadi — 2.5, 12.1). Nega client'da (server auth() o'rniga — Misol 3): navbar — interaktiv (foydalanuvchi kirsa/chiqsa darrov o'zgarishi kerak — masalan "Chiqish" bossa, navbar darrov "Kirish"ga o'zgaradi — sahifani qata yuklamacdan), va u ko'p sahifada ko'rinadi (umumiy — layout'da). useSession client'da sessiyani "jonli" boshqaradi (kirish/chiqish darrov aks etadi). Server'da auth() (Misol 3) — bir martalik tekshiruv (sahifa render paytida), client'da useSession — uzluksiz (interaktiv). Qachon qaysi 2.5-bob: server auth() — sahifa himoyasi (tekshir redirect — bir marta); client useSession — interaktiv UI (navbar, foydalanuvchi holatiga qarab — uzluksiz). Ko'p ilovada ikkalasi: server'da himoya (Misol 3), client'da interaktiv navbar (bu Misol). SessionProvider faqat client useSession uchun kerak (server auth() provayder talab qilmaydi). Bu — auth'ning client tomoni (interaktiv foydalanuvchi holati).
Misol 7 — Ro'yxatdan o'tish (signup — bcrypt — 2.10)
Maqsad: Yangi foydalanuvi ro'yxatdan o'tkazish — parolni bcrypt bilan hash qilib saqlash. Bu Credentials login (Misol 2)ning jufti (ro'yxat login).
// app/register/actions.ts — ro'yxatdan o'tish (Server Action)
"use server";
import bcrypt from "bcryptjs";
import { z } from "zod";
import { redirect } from "next/navigation";
const RegisterSchema = z.object({
name: z.string().min(2),
email: z.string().email(),
password: z.string().min(6, "Parol kamida 6 belgi"),
});
export async function register(prevState: any, formData: FormData) {
// 1. Validatsiya (Zod):
const parsed = RegisterSchema.safeParse(Object.fromEntries(formData));
if (!parsed.success) return { error: parsed.error.issues[0].message };
const { name, email, password } = parsed.data;
// 2. Email band emasligini tekshir:
const existing = await db.user.findUnique({ where: { email } });
if (existing) return { error: "Bu email allaqachon ro'yxatdan o'tgan" };
// 3. Parolni HASH qilib saqla (HECH QACHON ochiq — 2.10):
const passwordHash = await bcrypt.hash(password, 10); // 10 — salt rounds
await db.user.create({
data: { name, email, passwordHash, role: "user" }, // hash saqlanadi, ochiq parol YO'Q
});
redirect("/login?registered=true"); // ro'yxatdan keyin login'ga
}Bu kod nima qiladi: Bu — ro'yxatdan o'tish (signup — parol hash bilan — 2.10; Misol 2 Credentials login'ning jufti). register Server Action (forma bilan — 13.5): (1) validatsiya — Zod (RegisterSchema.safeParse — ism, email, parol to'g'rimi — Object.fromEntries(formData) formani obyektga aylantiradi); noto'g'ri bo'lsa xato qaytaradi; (2) email band emasligini tekshir — db.user.findUnique (email bo'yicha); agar mavjud bo'lsa xato ("allaqachon ro'yxatdan o'tgan" — bir email bir marta); (3) parolni hash qilib saqla — bcrypt.hash(password, 10) (2.10 — parolni hash qiladi — 10 salt rounds — qancha "qiyin" — yuqori = xavfsizroq, lekin sekinroq), keyin db.user.create bilan hashni saqlaydi (passwordHash — ochiq parol hech qaerda saqlanmaydi), va role: "user" (default rol). Keyin redirect("/login?registered=true") (ro'yxatdan keyin login sahifasiga — ?registered=true bilan "muvaffaqiyatli ro'yxatdan o'tdingiz" xabari uchun). Eng muhim xavfsizlik 2.10-bob: parol hech qachon ochiq saqlanmaydi — bcrypt.hash bilan bir tomonlama (irreversible) hash qilinadi (hash'dan parolni teskari ocha bo'lmaydi). Login'da (Misol 2) bcrypt.compare bilan tekshiriladi (kiritgan parolni hash qilib, saqlangan hash bilan solishtirish). Agar ochiq parol saqlasangiz va DB sizsa — barcha foydalanuvchi paroli ochiq (falokat — odamlar o'sha parolni boshqa saytlarda ham ishlatadi). Bu — ro'yxat login juftining ro'yxat qismi (Credentials uchun). Email band emasligini tekshirish (takror oldini), parol hash (xavfsizlik), validatsiya (Zod — to'g'ri ma'lumot) — uchalasi ham muhim. OAuth (Misol 1)da ro'yxat avtomatik (Google boshqaradi — parol yo'q), Credentials'da esa siz qilasiz (bu Misol). Parol hash — autentifikatsiya xavfsizligining eng asosiy qoidasi.
Misol 8 — Rol bilan callback (sessiyaga rol — 2.6)
Maqsad: Foydalanuvchi rolini sessiyaga qo'shish — callbacklar orqali. Bu avtorizatsiya (Misol 3, 4, 5)ning asosi (rol sessiyada bo'lishi shart).
// auth.ts — callbacks (rolni sessiyaga olib chiqish)
export const { handlers, auth } = NextAuth({
providers: [/* ... */],
session: { strategy: "jwt" },
callbacks: {
// jwt — token yaratilganda (login) rolni DB'dan token'ga:
async jwt({ token, user }) {
if (user) { // birinchi marta (login)
token.role = user.role; // rol token'da saqlanadi
token.id = user.id;
}
return token;
},
// session — token'dagi rolni sessiyaga (komponentda ishlatish uchun):
async session({ session, token }) {
if (session.user) {
session.user.role = token.role as string; // endi session.user.role bor
session.user.id = token.id as string;
}
return session;
},
},
});
// TypeScript — sessiya tipini kengaytirish (types/next-auth.d.ts):
// declare module "next-auth" {
// interface Session { user: { id: string; role: string } & DefaultSession["user"] }
// }Bu kod nima qiladi: Bu — rolni sessiyaga qo'shish (callbacklar — avtorizatsiyaning asosi — 2.6). Default'da Auth.js sessiyaga faqat name/email/image qo'yadi — lekin avtorizatsiya (Misol 3, 4, 5 — session.user.role)ning ishlashi uchun rol sessiyada bo'lishi kerak. Buni callbacklar qiladi: (1) jwt callback — token yaratilganda (login paytida — user mavjud — DB'dagi foydalanuvchi): token.role = user.role; token.id = user.id — rolni va ID'ni token'ga qo'shadi (token cookie'da — keyingi so'rovlarda DB'siz o'qiladi — JWT strategiya — 2.4); (2) session callback — sessiya o'qilganda: session.user.role = token.role — token'dagi rolni sessiyaga ko'chiradi (endi session.user.role mavjud — har joyda — Misol 3, 4, 5'da ishlatilgan). Natija: const session = await auth(); session.user.role — avtorizatsiya uchun rol mavjud (callbacklarsiz — undefined — avtorizatsiya ishlamasdi). Va TypeScript — sessiya tipini kengaytirish (types/next-auth.d.ts — interface Sessionga role qo'shish) — TypeScript session.user.roleni taniydi (xato bermaydi — 11.14). Nega ikki callback: jwt (token'ga — bir marta, login paytida — DB'dan rol olib token'ga solish), session (token'dan sessiyaga — har o'qishda — komponentga berish). JWT strategiyada 2.4-bob rol token'da (DB'siz o'qiladi — tez), database strategiyada esa boshqacharoq (DB'dan). Bu — autentifikatsiya (Auth.js — kim) va avtorizatsiya (rol — 2.1)ni bog'laydigan kalit qadam (rol sessiyaga qo'shilgach, har joyda (Misol 3, 4, 5) ruxsat tekshirsa bo'ladi). Callbacksiz rol-asosli avtorizatsiya ishlamaydi (rol sessiyada yo'q). Bu — Auth.js'ni o'z ilovangizning ruxsat tizimiga moslashtirishning asosi.
Misol 8b — Prisma sxema + Email magic link + WebAuthn (2.7, 2.11, 2.12)
Maqsad: Adapter uchun DB sxemasini ko'rsatish va parolsiz provayderlarni (magic link, passkey) sozlash. Bu OAuth va Credentials'dan tashqari zamonaviy, xavfsiz login usullari.
// prisma/schema.prisma — Auth.js standart sxema (2.7, 2.12)
model User {
id String @id @default(cuid())
name String?
email String? @unique
emailVerified DateTime?
image String?
role String @default("user") // avtorizatsiya uchun (2.6)
passwordHash String? // Credentials uchun (2.3, 2.10)
accounts Account[]
sessions Session[]
}
model Account { // OAuth hisoblari (access_token, refresh_token — 2.12)
userId String
provider String
providerAccountId String
refresh_token String? @db.Text
access_token String? @db.Text
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
@@id([provider, providerAccountId])
}
model Session { // database strategiyada (2.4)
sessionToken String @unique
userId String
expires DateTime
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
}
model VerificationToken { // magic link / email tasdiq (2.11)
identifier String
token String @unique
expires DateTime
@@unique([identifier, token])
}// auth.ts — parolsiz provayderlar (magic link + passkey — 2.11)
import NextAuth from "next-auth";
import Resend from "next-auth/providers/resend";
import Passkey from "next-auth/providers/passkey";
import { PrismaAdapter } from "@auth/prisma-adapter";
import { db } from "@/lib/db";
export const { handlers, auth, signIn, signOut } = NextAuth({
adapter: PrismaAdapter(db), // VerificationToken kerak (magic link)
experimental: { enableWebAuthn: true }, // WebAuthn/passkey yoqish (v5)
providers: [
Resend({ from: "no-reply@sayt.com" }), // magic link — email'ga havola
Passkey, // barmoq izi / Face ID / xavfsizlik kaliti
],
});Bu kod nima qiladi: Bu — adapter DB sxemasi (2.7, 2.12) va parolsiz provayderlar 2.11-bob. Prisma sxema — Auth.js adapter to'rt jadval bilan ishlaydi: User (foydalanuvchi — bu yerga role (avtorizatsiya — 2.6) va passwordHash (Credentials — 2.10) qo'shilgan), Account (OAuth hisoblari — access_token/refresh_token shu yerda — 2.12; @@id([provider, providerAccountId]) — bir provayder hisobi bir marta), Session (database strategiyada — 2.4), VerificationToken (magic link tokenlari — 2.11). Bu sxema Auth.js hujjatidan olinadi (nusxa prisma migrate jadvallar yaratiladi — 6.12). auth.ts — ikki parolsiz provayder: (1) Resend (magic link) — foydalanuvchi email kiritsa, unga havola yuboriladi (from — jo'natuvchi; Resend API kaliti env'da), havolani bossa kirdi (parol yo'q — VerificationToken jadvali havolani boshqaradi); (2) Passkey (WebAuthn — experimental: { enableWebAuthn: true } bilan) — qurilma (barmoq izi, Face ID) yoki xavfsizlik kaliti bilan kirish (eng xavfsiz — fishing'ga chidamli). Bu — zamonaviy, parolsiz autentifikatsiya (parol boshqaruvining og'irligi va xavfini yo'qotadi). OAuth (Misol 1) va Credentials (Misol 2)dan farqli — bu yerda foydalanuvchi parol eslab qolmaydi (magic link — email; passkey — qurilma). Ko'p zamonaviy sayt shu tomonga o'tmoqda (passkey — parolning kelajakdagi o'rnini bosuvchi). Sxema va provayder birga — Auth.js'ning to'liq ma'lumot qatlami (DB + login usullari).
Misol 8c — signIn callback + xato sahifasi (kirishni cheklash — 2.6, sahifalar)
Maqsad: signIn callback bilan kimlar kira olishini cheklash va maxsus xato sahifasini ko'rsatish. Bu kirish siyosatini (masalan bloklangan foydalanuvchini rad etish) markaziy boshqarish uchun.
// auth.ts — signIn callback + maxsus sahifalar
export const { handlers, auth } = NextAuth({
providers: [/* Google, GitHub — Misol 1 */],
pages: {
signIn: "/login", // maxsus login sahifasi (Misol 9)
error: "/auth/error", // maxsus xato sahifasi (default o'rniga)
},
callbacks: {
// signIn — kirishga RUXSAT berishdan oldin tekshir (true kirsin, false rad):
async signIn({ user, account }) {
// 1. Faqat tasdiqlangan email domenlari (masalan korporativ ilova):
if (account?.provider === "google" && !user.email?.endsWith("@kompaniya.uz")) {
return false; // rad error sahifasiga (AccessDenied)
}
// 2. Bloklangan foydalanuvchini rad et:
const dbUser = await db.user.findUnique({ where: { email: user.email! } });
if (dbUser?.banned) return false;
return true; // ruxsat kirsin
},
},
});Bu kod nima qiladi: Bu — signIn callback (kirish siyosati) va maxsus xato sahifasi. pages — Auth.js standart sahifalari o'rniga o'z sahifalaringiz: signIn: "/login" (login — Misol 9), error: "/auth/error" (xato sahifasi — masalan OAuth xatosi, kirish rad etilganda ko'rsatiladi — ?error=AccessDenied query bilan). signIn callback — bu foydalanuvchi login qilishga urinsa, Auth.js sessiya yaratishdan oldin chaqiriladi va true/false qaytaradi (true — kirsin, false — rad — error sahifasiga). Ikki misol: (1) domen cheklovi — masalan korporativ ilovada faqat @kompaniya.uz email'li Google hisoblari kira olsin (boshqasi rad); (2) bloklangan foydalanuvchi — DB'da banned bo'lsa rad et (u sessiya ololmaydi). Farqi (Credentials authorizedan — 2.3): authorize faqat Credentials'da parol tekshiradi, signIn callback esa barcha provayderlar (OAuth ham) uchun ishlaydi — yagona, markaziy kirish siyosati. Bu — kimlar tizimga kira olishini nazorat qilish (autentifikatsiyadan ham oldingi filtr — masalan taklif orqali ro'yxat, domen cheklovi, ban). Maxsus xato sahifasi esa foydalanuvchiga tushunarli xabar beradi (Auth.js standart sahifasi o'rniga — brend, til, dizayn sizniki). Bu callbacklar 2.6-bob va sahifalar (pages) — Auth.js'ni kirish siyosati va UX bo'yicha to'liq moslashtiradi.
Misol 9 — To'liq login sahifasi (UI + Server Action — 2.8)
Maqsad: To'liq login sahifani qurish — OAuth tugmalari + email/parol formasi. Bu foydalanuvi ko'radigan real auth interfeysi.
// app/login/page.tsx — login sahifasi (server)
import { signIn } from "@/auth";
export default function LoginPage() {
return (
<div className="login">
<h1>Kirish</h1>
{/* 1. OAUTH (Server Action — forma — 2.8): */}
<form action={async () => { "use server"; await signIn("google", { redirectTo: "/dashboard" }); }}>
<button>Google bilan kirish</button>
</form>
<form action={async () => { "use server"; await signIn("github", { redirectTo: "/dashboard" }); }}>
<button>GitHub bilan kirish</button>
</form>
<div className="divider">yoki</div>
{/* 2. CREDENTIALS (email/parol — Server Action): */}
<form action={async (formData: FormData) => {
"use server";
await signIn("credentials", {
email: formData.get("email"),
password: formData.get("password"),
redirectTo: "/dashboard",
});
}}>
<input name="email" type="email" placeholder="Email" required />
<input name="password" type="password" placeholder="Parol" required />
<button type="submit">Kirish</button>
</form>
<a href="/register">Hisobingiz yo'qmi? Ro'yxatdan o'ting</a>
</div>
);
}Bu kod nima qiladi: Bu — to'liq login sahifasi (foydalanuvchi ko'radigan real auth interfeysi — 2.8). Uch login usuli, hammasi Server Action (forma — progressive enhancement — 13.5: 2.5): (1) Google OAuth — <form action={async () => { "use server"; await signIn("google", { redirectTo: "/dashboard" }) }}> (Google bilan kirish tugmasi — bosilsa Google'ga yo'naltiriladi, tasdiqlab qaytgach dashboard'ga — redirectTo); (2) GitHub OAuth — xuddi shunday (signIn("github")); (3) Credentials (email/parol) — forma formData bilan: signIn("credentials", { email: formData.get("email"), password: ..., redirectTo: "/dashboard" }) — email/parol Auth.js'ning authorize funksiyasiga boradi (Misol 2 — bcrypt tekshiruvi), to'g'ri bo'lsa dashboard'ga. Va "Ro'yxatdan o'ting" havolasi (yangi foydalanuvchi uchun — Misol 7). Nega Server Action (client signIn o'rniga): progressive enhancement (forma JavaScript'siz ham ishlaydi — 13.5: 2.5 — sekin internet, JS yuklanmagan holda ham login mumkin — ishonchli, accessibility), sodda (alohida client state yo'q). Bu — real saytlarning login sahifasi (Google/GitHub — tez, parolsiz; email/parol — an'anaviy — foydalanuvchi tanlaydi). Ko'p usul berish yaxshi UX (foydalanuvchi qulayini tanlaydi — ba'zi odamlar Google'ni afzal ko'radi — parol eslab qolish yo'q, ba'zilari email/parol — nazorat). signIn Auth.js'ning kirish funksiyasi (OAuth oqimi yoki credentials tekshiruvi — avtomatik). Bu — autentifikatsiya interfeysining (foydalanuvchí ko'radigan qism) to'liq namunasi. Dizayn (CSS) qo'shilsa — professional login sahifa.
Misol 10 — To'liq auth tizimi (hammasi birga)
Maqsad: To'liq autentifikatsiya tizimini ko'rsatish — sozlash, himoya, rol, har qatlam. Bu butun bobning amaliy yakuni (production auth arxitekturasi).
// === 1. auth.ts (sozlama — Misol 1, 2, 8) ===
export const { handlers, auth, signIn, signOut } = NextAuth({
adapter: PrismaAdapter(db),
providers: [Google, Credentials({ authorize: /* bcrypt — Misol 2 */ })],
session: { strategy: "jwt" },
callbacks: { jwt: /* rol — Misol 8 */, session: /* rol — Misol 8 */ },
pages: { signIn: "/login" },
});
// === 2. middleware.ts (markaziy himoya — Misol 4) ===
export default auth((req) => {
if (req.nextUrl.pathname.startsWith("/dashboard") && !req.auth) /* login */;
if (req.nextUrl.pathname.startsWith("/admin") && req.auth?.user?.role !== "admin") /* / */;
});
// === 3. Server Component (sahifa himoya — Misol 3) ===
// const session = await auth(); if (!session) redirect("/login");
// === 4. Server Action (avtorizatsiya — Misol 5) ===
// "use server"; await requireAdmin(); /* amal */
// === 5. Client (navbar — Misol 6) ===
// "use client"; const { data: session } = useSession();
// HIMOYA QATLAMLARI (defense in depth — 2.9):
// Middleware (markaziy, tez) Server Component (sahifa) Server Action (mutation)
// har qatlam mustaqil himoyalangan (biri aylanib o'tilca — keyingi ushlaydi)Bu kod nima qiladi: Bu — butun bobning amaliy yakuni (to'liq, production auth arxitekturasi — barcha qism birga). Besh komponent: (1) auth.ts (sozlama — Misol 1, 2, 8) — provayderlar (Google OAuth + Credentials bcrypt bilan), JWT sessiya, rol callbacklari (sessiyaga rol — avtorizatsiya uchun), maxsus login sahifasi; (2) middleware.ts (markaziy himoya — Misol 4) — /dashboard (kirgan kerak — autentifikatsiya), /admin (admin kerak — avtorizatsiya) — birinchi, tez qatlam; (3) Server Component (sahifa himoyasi — Misol 3) — auth() bilan sessiyani tekshirib, kirmaganni redirect; (4) Server Action (avtorizatsiya — Misol 5) — requireAdmin() har mutation'da (ochiq endpoint — 13.5: 2.11); (5) Client (navbar — Misol 6) — useSession bilan interaktiv UI. Eng muhim g'oya — himoya qatlamlari (defense in depth — chuqur himoya — 2.9, 14-QISM): middleware (markaziy, tez — birinchi) Server Component (sahifa — ikkinchi) Server Action (mutation — uchinchi) — har qatlam mustaqil himoyalangan (biri aylanib o'tilsa — keyingi ushlaydi). Masalan: agar kimdir middleware'ni aylanib o'tsa (texnik usul bilan), Server Component uni ushlaydi; agar sahifani aylanib o'tsa (Server Action'ni to'g'ridan chaqirsa), Server Action'ning requireAdmin ushlaydi. Eng keng xato — faqat bir qatlamga ishonish (masalan faqat middleware — yoki faqat UI yashirish) — har qatlam zarur (UI — UX, middleware — markaziy, Server Action — haqiqiy himoya). Bu — production autentifikatsiya tizimining to'liq arxitekturasi: Auth.js (sozlama, provayder, sessiya — murakkab ishni qiladi) + har qatlamda tekshiruv (siz qo'shasiz — UI, middleware, sahifa, Server Action). Autentifikatsiya (kim) + avtorizatsiya (nima qila oladi) + chuqur himoya (har qatlam) = xavfsiz foydalanuvchi tizimi. Har real ilova (e-commerce, ijtimoiy tarmoq, SaaS) shunday quriladi. 14-QISM (Xavfsizlik)da bu yondashyv (defense in depth) chuqurroq ochiladi.
5. To'g'ri va noto'g'ri holatlar
1) Parol
ochiq parol DB'da (DB sizsa — falokat — 2.10)
bcrypt.hash (hash saqlanadi — Misol 7)2) Avtorizatsiya joyi
faqat UI yashirish (Server Action ochiq — 2.9)
har qatlamda tekshir (sahifa + Server Action/API — Misol 5, 10)3) Sessiyani olish
client useSession sahifa himoyasiga (kontent yuboriladi)
server auth() (himoya — xavfsiz, tez — Misol 3)4) Rol
rol sessiyada yo'q (callbacksiz — avtorizatsiya ishlamaydi)
callbacks (jwt + session — rol — Misol 8)5) Secret
AUTH_SECRET kodda yoki zaif (token buziladi)
env'da kuchli (npx auth secret — 2.10)6) OAuth vs Credentials
Credentials'ni bcrypt'siz (ochiq parol — xavfli)
OAuth afzal (parol siz saqlamaysiz) yoki Credentials + bcrypt (2.3)6. Keng tarqalgan xatolar va yechimlari
Xato 1 — session is null (kirgan bo'lsa ham)
Sababi: SessionProvider yo'q (client) yoki auth() noto'g'ri import 2.5-bob. Yechimi: server auth(); client SessionProvider (Misol 6).
Xato 2 — session.user.role undefined
Sababi: callbacks yo'q (rol sessiyada emas — 2.6). Yechimi: jwt + session callbacks (Misol 8).
Xato 3 — Oddiy foydalanuvchi admin amalini bajardi
Sababi: Server Action rol tekshirmaydi (faqat UI yashirilgan — 2.9). Yechimi: requireAdmin har Server Action'da (Misol 5).
Xato 4 — OAuth redirect xatosi (callback URL)
Sababi: provayder console'da callback URL noto'g'ri. Yechimi: https://sayt.com/api/auth/callback/google (provayder sozlamasida).
Xato 5 — AUTH_SECRET xatosi
Sababi: secret yo'q yoki noto'g'ri 2.10-bob. Yechimi: .envda AUTH_SECRET (npx auth secret).
Xato 6 — Parol tekshiruvi har doim false
Sababi: ochiq parol vs hash solishtirildi 2.10-bob. Yechimi: bcrypt.compare (hash bilan — Misol 2).
Xato 7 — Middleware sessiyani ko'rmaydi
Sababi: auth middleware noto'g'ri 2.9-bob. Yechimi: export default auth((req) => ...) (req.auth — Misol 4).
7. Integratsiya — bu mavzu stack'ning qayerida uchraydi
- Middleware 13.6-bob: auth middleware — markaziy himoya (Misol 4).
- Server Actions 13.5-bob: Server Action avtorizatsiya (rol — Misol 5).
- Server Components 13.3-bob: auth() — server'da sessiya (Misol 3).
- Routing 13.2-bob: redirect — himoyalangan sahifa.
- DB/Prisma 6.12-bob: adapter — foydalanuví/sessiya DB'da.
- Forms (13.5, 11.10): login/register forma + validatsiya (Zod).
- Xavfsizlik (14): parol hash, CSRF, avtorizatsiya (chuqur).
- Context 12.1-bob: SessionProvider — client sessiya.
8. Eng yaxshi amaliyotlar (best practices)
- OAuth afzal (parol siz saqlamaysiz — xavfsizroq — 2.3).
- Parol hash (bcrypt) (ochiq emas — 2.10, Misol 7).
- Avtorizatsiya har qatlamda (middleware + sahifa + Server Action — 2.9, Misol 10).
- Server auth() afzal (xavfsiz, tez — Misol 3); client useSession interaktiv.
- Rol callbacks orqali (sessiyaga — 2.6, Misol 8).
- AUTH_SECRET kuchli (env'da — 2.10).
- HTTPS production (cookie/token himoya — 2.10).
- Validatsiya (Zod) (login/register — Misol 2, 7).
- Sessiya muddati (maxAge — cheksiz emas — 2.10).
- Defense in depth (har qatlam mustaqil himoya — Misol 10).
9. Amaliy loyiha: "To'liq Auth Tizimi"
Auth.js bilan to'liq foydalanuvchi tizimini mustahkamlash.
Maqsad
Ilova: ro'yxat/login (OAuth + email/parol), himoyalangan sahifalar, admin panel, rollar.
Talablar (requirements)
- Sozlash: Auth.js + Prisma adapter + Google + Credentials (Misol 1, 2).
- Ro'yxat: email/parol + bcrypt hash (Misol 7).
- Login: OAuth + email/parol sahifasi (Misol 9).
- Sessiya: server auth() + client useSession (Misol 3, 6).
- Rollar: callbacks (sessiyaga rol — Misol 8).
- Sahifa himoya: dashboard (kirgan) — Misol 3.
- Middleware: markaziy himoya (dashboard/admin — Misol 4).
- Server Action: admin amallar (avtorizatsiya — Misol 5).
- Navbar: kirgan/kirmagan UI (Misol 6).
- Xavfsizlik: secret, HTTPS, defense in depth (Misol 10).
Maslahatlar (hint)
- Parol bcrypt (ochiq emas — Xato 6).
- Rol callbacks (Xato 2).
- Avtorizatsiya har qatlamda (faqat UI emas — Xato 3).
- Server auth() himoyaga (Misol 3).
- AUTH_SECRET env (Xato 5).
- OAuth callback URL to'g'ri (Xato 4).
"Tayyor" mezonlari (acceptance criteria)
- OAuth + Credentials login.
- Ro'yxat (bcrypt hash).
- Server + client sessiya.
- Rollar (callbacks).
- Sahifa himoya (server).
- Middleware (markaziy).
- Server Action avtorizatsiya.
- Defense in depth (har qatlam).
Yechim kodi ataylab berilmagan — bu loyihani o'zingiz yozib ko'ring.
10. Xulosa va keyingi bobga ko'prik
Bu bobda Next.js'da autentifikatsiyani (Auth.js) chuqur o'rgandik:
- Authn vs authz 2.1-bob; Auth.js sozlash 2.2-bob; provayderlar (OAuth/Credentials — 2.3); sessiya strategiya (JWT/database — 2.4); sessiyani olish (server/client — 2.5).
- Callbacklar (rol, signIn — 2.6); adapter 2.7-bob; kirish/chiqish 2.8-bob; avtorizatsiya (rollar — 2.9); xavfsizlik (bcrypt/CSRF — 2.10).
- Boshqa provayderlar (magic link/passkey/Discord — 2.11); DB sxema, env, token refresh 2.12-bob; Next.js vs backend auth (NestJS — 2.13); muqobillar (Clerk/Lucia/Supabase — 2.14).
Endi siz Next.js'da to'liq foydalanuvchi tizimini qura olasiz: login/ro'yxat (OAuth + email/parol), himoyalangan sahifalar, rollar, va chuqur himoya (har qatlam). Bu — har real ilovaning asosiy qismi.
Keyingi bob — 13.10-bob: Deploy va Production. Auth'ni bildik; endi ilovani dunyoga chiqarishni ko'ramiz: Vercel'da deploy (eng oson — Next.js yaratuvchilari), environment variables (secret production'da), build optimizatsiya, boshqa platformalar (Docker, o'z server — 10-QISM bilan), domen va HTTPS, monitoring va xatolar (logging, analytics), va production checklist. Bu — loyihangizni real foydalanuvchilarga yetkazishning yakuniy qadami.
Foydalanilgan rasmiy/ishonchli manbalar
- Auth.js rasmiy hujjati — "Getting Started", "Providers" (OAuth, Credentials, Email/magic link, WebAuthn/passkey), "Session strategies" (JWT vs database), "Callbacks" (jwt, session, signIn), "Adapters", "Pages" (custom signIn/error), "TypeScript" (module augmentation)
- Next.js rasmiy hujjati — "Authentication" bo'limi, middleware bilan auth, Server Components'da sessiya
- OWASP — Authentication Cheat Sheet va Session Management Cheat Sheet (parol hash, sessiya xavfsizligi); bcrypt/argon2 hujjatlari
- Prisma adapter va standart DB sxemasi (User/Account/Session/VerificationToken); Drizzle adapter
- OAuth 2.0 / OpenID Connect spetsifikatsiyasi; provayder developer console'lari (Google, GitHub, Discord — clientId/secret, callback URL)
- Muqobil yechimlar hujjatlari: Clerk, Lucia, Supabase Auth (taqqoslash uchun)
Izohlar (0)
Izoh yozish uchun kiring.
- Hozircha izoh yo'q. Birinchi bo'ling!