Praktik 10: NextAuth
Materi Praktik 10 mengonfigurasi NextAuth dengan penyedia Credentials, lalu menyambungkannya ke fungsi verifikasi dan pembuatan token dari Praktik 9.
Berkas yang diperiksa, semuanya di Praktik 10/Konfigurasi NextAuth/File Latihan/:
route.js, providers.js, proxy.js, layout.js, theme.js, dan package.json.
P10-1. verifyAccessToken dipanggil tanpa diimpor (Kritikal)
Section titled “P10-1. verifyAccessToken dipanggil tanpa diimpor (Kritikal)”route.js hanya mengimpor dua nama:
import { verifyCredentials } from "../../../../../lib/auth/verifyCredentials";import { signAccessToken } from "../../../../../lib/auth/jwt";Tetapi di dalam callback jwt, baris 46 memanggil nama ketiga:
try { verifyAccessToken(token.accessToken); // Cek validitas} catch (err) { token.accessToken = signAccessToken({ user_id: token.id, email: token.email, role: token.role, });}verifyAccessToken tidak pernah diimpor, sehingga setiap permintaan sesi melempar
ReferenceError, dan catch menangkapnya.
Akibatnya accessToken dibuat ulang pada setiap permintaan, bukan hanya saat sudah kedaluwarsa.
Login tetap berhasil, sehingga bug ini tidak terlihat kecuali ada yang memperhatikan tokennya
terus berganti. Blok catch yang seharusnya menangani token kedaluwarsa berubah menjadi jalur
yang selalu dijalankan.
P10-2. session.user.user_id selalu undefined (Tinggi)
Section titled “P10-2. session.user.user_id selalu undefined (Tinggi)”Callback jwt mengisi token.id:
token.id = user.user_id;Callback session membacanya dari kunci yang berbeda:
session.user.id = token.id;session.user.user_id = token.user_id;token.user_id tidak pernah ditulis di mana pun, sehingga session.user.user_id selalu
undefined. Kode yang membaca session.user.user_id akan menerima undefined tanpa pesan
galat apa pun.
P10-3. accessToken ikut terkirim ke browser (Tinggi)
Section titled “P10-3. accessToken ikut terkirim ke browser (Tinggi)”async session({ session, token }) { session.user.role = token.role; session.accessToken = token.accessToken; return session;}Nilai yang dikembalikan callback session dikirim ke klien dan bisa dibaca lewat
/api/auth/session. Ini menempatkan bearer token aplikasi di jangkauan JavaScript halaman, dan
menghapus salah satu manfaat menyimpannya di dalam cookie httpOnly.
Satu temuan yang sama sudah tercatat pada daftar bug modul di troubleshooting.md nomor 36.
P10-4. crypto sebagai dependensi npm (Sedang)
Section titled “P10-4. crypto sebagai dependensi npm (Sedang)”package.json baris 23 memuat "crypto": "^1.0.1". Paket itu deprecated dan tidak dipakai di
mana pun pada kode praktik ini.
P10-5. pages.signIn bergantung pada NEXTAUTH_URL (Sedang)
Section titled “P10-5. pages.signIn bergantung pada NEXTAUTH_URL (Sedang)”providers.js memakai basePath="/portal/api/auth" dan proxy.js memakai basePath="/portal".
Dua nilai itu memang berbeda dan benar: yang pertama letak endpoint NextAuth, yang kedua letak
halaman aplikasi.
Yang perlu diperhatikan, pages: { signIn: "/login" } akan menjadi /portal/login. NextAuth
menghitung alamat pengalihan dari NEXTAUTH_URL, sehingga nilai itu harus memuat /portal.
Praktik 11 memakai dua bentuk untuk variabel yang sama:
| Lokasi | Nilai |
|---|---|
.env.example |
NEXTAUTH_URL=http://IP_EKSTERNAL_VM/portal/ |
| Tahap 13 bagian 3 | NEXTAUTH_URL=https://SUBDOMAIN/portal |
Perbedaan slash di akhir cukup untuk membuat callbackUrl berbeda.
P10-6. check-config.mjs butuh paket yang tidak terpasang (Sedang)
Section titled “P10-6. check-config.mjs butuh paket yang tidak terpasang (Sedang)”Berkas scripts/check-config.mjs pada Praktik 11 memuat:
const YAML = createRequire(import.meta.url)('yaml');Paket yaml tidak ada di dependencies maupun devDependencies pada package.json. Perintah
node scripts/check-config.mjs yang diminta materi akan berhenti dengan
Error: Cannot find module 'yaml'.
Node 24 juga tidak punya parser YAML bawaan, jadi tidak ada cadangan.
P10-7. Materi belum selesai (Rendah)
Section titled “P10-7. Materi belum selesai (Rendah)”Konfigurasi NextAuth.docx berisi 10 baris dan diakhiri dua baris yang hanya memuat huruf A.
Bagian penutupnya kosong.
Solusi
Section titled “Solusi”Untuk P10-1, verifyAccessToken tanpa impor
Section titled “Untuk P10-1, verifyAccessToken tanpa impor”Tambahkan nama itu pada baris impor yang sudah ada:
import { signAccessToken, verifyAccessToken } from "../../../../../lib/auth/jwt";Ini satu-satunya perubahan yang benar-benar memblokir. Tanpa perbaikan ini, callback jwt
melempar ReferenceError pada setiap permintaan sesi, dan blok catch yang seharusnya menangani
token kedaluwarsa berubah menjadi jalur yang selalu dijalankan.
Sekaligus perbaiki alur di dalam callback agar token hanya dibuat ulang bila memang sudah tidak sah:
if (!token.accessToken) { token.accessToken = signAccessToken({ user_id: token.id, email: token.email, role: token.role }); return token;}
try { verifyAccessToken(token.accessToken);} catch { token.accessToken = signAccessToken({ user_id: token.id, email: token.email, role: token.role });}Cara memastikan perbaikannya bekerja: pantau nilai accessToken pada dua permintaan berturut.
Sebelum diperbaiki nilainya selalu berubah. Sesudah diperbaiki nilainya tetap sampai tokennya
benar-benar kedaluwarsa.
Untuk P10-2, session.user.user_id selalu undefined
Section titled “Untuk P10-2, session.user.user_id selalu undefined”Isi kuncinya saat login, lalu beri cadangan saat dibaca:
// di callback jwt, saat pertama kali logintoken.id = user.user_id;token.user_id = user.user_id;// di callback sessionsession.user.user_id = token.user_id ?? token.id;Berkas route.js memuat versi lengkapnya.
Untuk P10-3, accessToken terkirim ke browser
Section titled “Untuk P10-3, accessToken terkirim ke browser”Keluarkan dari callback session:
async session({ session, token }) { session.user.id = token.id; session.user.user_id = token.user_id ?? token.id; session.user.email = token.email; session.user.role = token.role; // accessToken tidak dimasukkan ke session return session;}Nilai yang dikembalikan callback session dikirim ke klien lewat /api/auth/session, sehingga
apa pun yang ditaruh di sana dapat dibaca JavaScript halaman. Bila komponen klien benar-benar
membutuhkan token, sediakan route terpisah yang memeriksa sesi lebih dahulu, dan jangan kirim
tokennya ke komponen.
Untuk P10-4, dependensi crypto
Section titled “Untuk P10-4, dependensi crypto”Hapus dari package.json:
"crypto": "^1.0.1",Di kode, pakai modul bawaan Node:
import { randomUUID } from "node:crypto";Untuk P10-5, NEXTAUTH_URL dua bentuk
Section titled “Untuk P10-5, NEXTAUTH_URL dua bentuk”Pilih satu bentuk dan pakai di semua tempat. Karena aplikasi dilayani di /portal, nilai yang
benar memuat path itu:
NEXTAUTH_URL=http://IP_STATIS_VM/portal/Saat HTTPS aktif, ganti menjadi:
NEXTAUTH_URL=https://SUBDOMAIN/portal/Perhatikan hubungan antara nilai ini dan cara aplikasi diakses. NextAuth menentukan nama cookie
dari protokol pada NEXTAUTH_URL, seperti terlihat pada source next-auth versi 4:
secureCookie = process.env.NEXTAUTH_URL?.startsWith("https://") ?? !!process.env.VERCEL;cookieName = secureCookie ? "__Secure-next-auth.session-token" : "next-auth.session-token";Bila NEXTAUTH_URL sudah https:// sedangkan aplikasi masih dibuka lewat http://, browser
menolak mengirim cookie bertanda Secure, dan gejalanya adalah sesi yang tampak tidak pernah
login tanpa pesan galat apa pun.
Untuk P10-6, check-config.mjs butuh paket yaml
Section titled “Untuk P10-6, check-config.mjs butuh paket yaml”Dua pilihan. Pertama, tambahkan paketnya:
npm install --save-dev yamlKedua, ganti skripnya dengan versi tanpa dependensi. Pilihan kedua lebih aman, karena skrip itu dimaksudkan untuk memeriksa konfigurasi sebelum commit, dan tidak seharusnya menuntut pemasangan tambahan lebih dahulu.
Berkas periksa-yaml.mjs adalah penggantinya, dengan keluaran setara dan satu pemeriksaan
tambahan: setiap variabel ${...} pada compose harus punya nilai di .env.example.
Untuk P10-7, materi belum selesai
Section titled “Untuk P10-7, materi belum selesai”Bagian penutup Konfigurasi NextAuth.docx masih berupa dua baris berisi huruf A. Bagian itu
perlu ditulis atau dihapus. Selama masih ada, pembaca tidak tahu apakah dokumennya lengkap.
Berkas siap pakai
Section titled “Berkas siap pakai”| Berkas | Isi |
|---|---|
Praktik 10/perbaikan/route.js |
Route NextAuth dengan impor lengkap dan sesi yang benar |
Praktik 10/tools/periksa-konfigurasi.mjs |
Periksa proxy.js, basePath, .env, dan dependensi |
Praktik 11/tools/periksa-yaml.mjs |
Pengganti check-config.mjs tanpa dependensi |
Ringkasan
Section titled “Ringkasan”| Butir | Tingkat | Inti |
|---|---|---|
| P10-1 | Kritikal | verifyAccessToken dipanggil tanpa diimpor |
| P10-2 | Tinggi | session.user.user_id selalu undefined |
| P10-3 | Tinggi | accessToken ikut terkirim ke browser |
| P10-4 | Sedang | Dependensi crypto tidak terpakai |
| P10-5 | Sedang | NEXTAUTH_URL ditulis dalam dua bentuk berbeda |
| P10-6 | Sedang | check-config.mjs butuh paket yang tidak terpasang |
| P10-7 | Rendah | Dokumen materi belum selesai |