Gerbang Proxy & Rewriting Rute
Lapisan penjaga di tingkat jaringan (Next.js Proxy) yang memvalidasi sesi JWT, mengatur hak akses halaman, dan menyamarkan struktur folder internal lewat URL rewrites.
Membaca sekitar 2 menit
Lapisan penjaga di tingkat jaringan (Next.js Proxy) yang memvalidasi sesi JWT, mengatur hak akses halaman, dan menyamarkan struktur folder internal lewat URL rewrites.
Semua request melewati lapisan proxy untuk memeriksa cookie sesi dan menyuntikkan security headers, sementara next.config.ts memetakan URL bersih seperti /dashboard ke struktur layout internal.
Pengguna yang baru lolos password tapi belum memasukkan OTP diberi status sesi 'pending' di dalam token agar tetap tertahan di gerbang proxy dan tidak bisa melompat langsung ke dashboard.
Masalahnya dulu
Di MyPocket, halaman setelah login memiliki dua tata letak yang berbeda: halaman pemilihan kantong tabungan (/saving) tampil penuh tanpa navigasi samping, sedangkan halaman seperti Dashboard, Pengeluaran, Pendapatan, Investasi, Analisis, dan Profil berada di dalam kerangka AppLayout (Sidebar, Topbar, dan MobileNav). Jika menggunakan struktur folder biasa, URL di browser akan mengekspos struktur direktori internal, sementara puluhan endpoint API dan halaman privat harus dijaga agar tidak bisa ditembus tanpa sesi yang sah.
Memisahkan tampilan lewat Rewrites dan menjaga pintu di Proxy
Untuk menjaga URL tetap bersih di mata pengguna namun tetap terorganisir di dalam satu layout grup, konfigurasi Next.js memetakan rute publik ke dalam direktori layout internal menggunakan fitur rewrites. Di saat yang sama, seluruh lalu lintas request dicegat terlebih dahulu oleh fungsi proxy (konvensi middleware di Next.js 16) untuk memverifikasi token JWT dari cookie httpOnly.
URL yang rapi adalah urusan rewrites di konfigurasi, tetapi siapa yang boleh melewatinya adalah keputusan mutlak di gerbang proxy.
Implementasi di ngodingan ini
Di dalam lapisan proxy, pengecekan status login tidak hanya melihat apakah token JWT valid, tetapi juga memastikan role di dalam token bukan 'pending' (yang menandakan pengguna baru lolos tahap password tetapi belum menyelesaikan verifikasi OTP):
export async function proxy(req: NextRequest) {
const { pathname } = req.nextUrl;
const token = req.cookies.get(SESSION_COOKIE)?.value ?? null;
const user = token ? await verifyToken(token) : null;
const isLoggedIn = !!user && user.role !== "pending";
if (PUBLIC_API.some((p) => pathname.startsWith(p))) {
return withSecurityHeaders(NextResponse.next());
}
if (pathname.startsWith("/api/")) {
if (!user) {
return NextResponse.json(
{ success: false, message: "Unauthorized" },
{ status: 401 }
);
}
return withSecurityHeaders(NextResponse.next());
}
if (!isLoggedIn) {
const loginUrl = new URL("/", req.url);
loginUrl.searchParams.set("redirect", pathname);
return NextResponse.redirect(loginUrl);
}
return withSecurityHeaders(NextResponse.next());
}Jebakan dan detail yang harus dijaga
- Membedakan antara user (token ada, termasuk yang berstatus 'pending') dan isLoggedIn (sudah lolos OTP). Tanpa pembedaan ini, pengguna yang baru memasukkan password bisa langsung mengetik /dashboard di address bar untuk melewati halaman OTP.
- Mengarahkan ulang pengguna yang sudah login (isLoggedIn) jika mereka mencoba kembali membuka halaman khusus tamu seperti /login atau /register agar langsung diarahkan ke halaman pemilihan tabungan.