# Konfigurasi CORS untuk Next.js dan NestJS: Benar di Produksi

> Mengkonfigurasi CORS dengan benar untuk frontend Next.js dan API NestJS — mencakup origins, credentials, caching preflight, dan miskonfigurasi yang menciptakan lubang keamanan nyata.

URL: https://www.matthewswong.com/id/blog/cors-configuration-nextjs-nestjs/

- Author: Matthews Wong (https://www.matthewswong.com/id/about/)
- Published: 2025-06-10
- Updated: 2025-06-10
- Category: DevOps

CORS (Cross-Origin Resource Sharing) adalah mekanisme keamanan browser yang mengontrol origin mana yang dapat membuat permintaan ke API Anda. Ini juga merupakan salah satu kontrol keamanan yang paling disalahpahami — developer sering cargo-cult konfigurasi dari StackOverflow tanpa memahami apa yang mereka izinkan. Miskonfigurasi CORS paling berbahaya yang saya lihat secara reguler: `Access-Control-Allow-Origin: *` dikombinasikan dengan `Access-Control-Allow-Credentials: true`.

## Apa yang CORS Sebenarnya Lakukan (dan Tidak Lakukan)

CORS adalah mekanisme penegakan browser. Ini TIDAK melindungi API Anda dari klien HTTP langsung (curl, Postman, permintaan server-ke-server) — yang mengabaikan header CORS sepenuhnya. CORS hanya membatasi permintaan lintas origin berbasis browser. Yang dilindunginya: cross-site request forgery (CSRF) untuk permintaan yang memiliki kredensial, situs jahat yang membaca respons API Anda menggunakan sesi browser korban.

### Masalah Credentials + Wildcard

Spesifikasi CORS browser secara eksplisit melarang `Access-Control-Allow-Origin: *` ketika `Access-Control-Allow-Credentials: true`. Jika API Anda menyajikan cookie atau header Authorization pada permintaan lintas origin dengan kredensial, Anda harus menentukan origin yang tepat. Ini berarti konfigurasi CORS Anda harus mempertahankan daftar origin yang diizinkan dan merespons secara dinamis dengan origin yang meminta jika ada dalam daftar.

> Dari pengalaman saya mengkonfigurasi CORS untuk API ERP: pertahankan daftar origin yang diizinkan dalam variabel lingkungan, bukan hardcoded. Untuk lingkungan staging, daftarnya mencakup localhost:3000, localhost:3001, dan domain staging. Untuk produksi, hanya domain frontend produksi. Ini mencegah kesalahan umum mendeploy konfigurasi CORS staging ke produksi.

## Konfigurasi CORS NestJS

NestJS menggunakan paket cors (middleware cors Express) di bawahnya. Konfigurasikan di main.ts dengan validasi origin eksplisit, batas metode, dan penanganan kredensial. Kunci adalah pola callback origin — ini memungkinkan Anda memeriksa origin yang meminta terhadap allowlist Anda dan mengembalikan error untuk origin yang tidak dikenal, daripada mengizinkan semua atau memblokir semua.

### Caching Preflight dan Optimasi OPTIONS

Permintaan preflight (OPTIONS) dikirim oleh browser sebelum permintaan lintas origin dengan kredensial atau non-sederhana. Setiap preflight menambahkan hit latensi round-trip. Konfigurasikan Access-Control-Max-Age untuk meng-cache hasil preflight — browser tidak akan mengirim ulang permintaan OPTIONS selama durasi ini. Saya menggunakan 600 detik (10 menit).

> **Peringatan Miskonfigurasi Umum**

> Miskonfigurasi CORS yang muncul dalam laporan penetration test nyata: menggunakan regex yang cocok dengan origin terlalu luas. Saya telah melihat konfigurasi seperti `origin.includes('mycompany.com')` yang akan mengizinkan `evil-mycompany.com` masuk. Selalu gunakan pencocokan string tepat atau sekumpulan origin yang divalidasi. Kesalahan umum lainnya: tidak membatasi metode yang diizinkan.

## CORS Next.js API Routes

Untuk API routes Next.js, header CORS tidak diatur secara otomatis — Anda perlu menambahkannya secara eksplisit. Pola yang direkomendasikan adalah pembungkus middleware CORS yang memvalidasi origin dan menetapkan header yang sesuai. Jika aplikasi Next.js dan API Anda berada di origin yang sama (yang seharusnya dalam sebagian besar kasus), Anda tidak memerlukan CORS sama sekali.

## Menguji Konfigurasi CORS Anda

Uji CORS dari konsol browser, bukan curl. Buka frontend produksi Anda di browser, buka DevTools, dan jalankan: `fetch('https://your-api.com/api/endpoint', '{method: ''POST'', credentials: ''include'', headers: {''Content-Type'': ''application/json''}', body: JSON.stringify('{test: true}')'}').then(r => r.json()).then(console.log)`. Jika berhasil dari origin frontend Anda dan gagal dari origin yang berbeda, CORS Anda dikonfigurasi dengan benar.

## CORS dan Interaksi Cookie SameSite

CORS dan atribut cookie SameSite bekerja bersama untuk keamanan kredensial. Dengan cookie SameSite=Strict, browser tidak akan mengirim cookie pada permintaan lintas origin mana pun, membuat konfigurasi kredensial CORS tidak relevan untuk cookie tersebut. Kombinasi yang saya gunakan untuk API ERP: refresh token dalam cookie httpOnly Strict Secure (same-origin saja), access token dalam memori (bukan cookie), allowlist CORS untuk origin frontend tertentu.

## Sumber & Bacaan Lanjutan

- MDN Web Docs — Cross-Origin Resource Sharing (CORS) — https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS
- OWASP — CORS Security Cheat Sheet — https://cheatsheetseries.owasp.org/cheatsheets/CORS_Security_Cheat_Sheet.html
- PortSwigger — CORS Vulnerabilities — https://portswigger.net/web-security/cors

## Source links

- https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS
- https://portswigger.net/web-security/cors

## FAQ

### Mengapa `Access-Control-Allow-Origin: *` tidak bisa digabungkan dengan `Access-Control-Allow-Credentials: true`?

Spesifikasi CORS browser secara eksplisit melarang kombinasi ini. Jika kredensial (cookie atau header Authorization) terlibat dalam permintaan lintas origin, Anda harus menentukan origin yang tepat, bukan wildcard. Browser modern akan menolak respons yang memadukan kedua header ini.

### Bagaimana cara mengelola daftar origin yang diizinkan di konfigurasi CORS NestJS?

Origin sebaiknya disimpan dalam variabel lingkungan, bukan hardcoded, dan divalidasi menggunakan pola callback origin yang memeriksa apakah origin peminta ada dalam allowlist. Lingkungan staging mencakup localhost:3000, localhost:3001, dan domain staging, sementara produksi hanya boleh berisi domain frontend produksi — ini mencegah konfigurasi CORS staging ter-deploy ke produksi.

### Apa fungsi `Access-Control-Max-Age` dan berapa nilai yang direkomendasikan?

Header ini memberi tahu browser berapa lama (dalam detik) hasil permintaan preflight OPTIONS di-cache, sehingga tidak perlu round-trip tambahan sebelum setiap panggilan lintas origin. Artikel ini merekomendasikan 600 detik (10 menit); Chrome mendukung hingga 7200 detik dan Firefox hingga 86400 detik.

### Apa contoh miskonfigurasi CORS berbasis regex dan bagaimana cara menghindarinya?

Menggunakan pengecekan substring seperti `origin.includes('mycompany.com')` berbahaya karena akan mengizinkan `evil-mycompany.com` lolos validasi. Selalu gunakan pencocokan string tepat atau sekumpulan string origin yang sudah divalidasi sebelumnya.

### Apakah API routes Next.js memerlukan konfigurasi CORS?

Hanya jika API dan frontend Next.js berada di origin yang berbeda. Jika keduanya berada di origin yang sama — yang merupakan setup umum — CORS tidak berlaku dan tidak ada header yang perlu ditambahkan. Jika akses lintas origin memang dibutuhkan, header harus ditambahkan secara eksplisit melalui middleware wrapper karena Next.js tidak menyetelnya secara otomatis.

---

- HTML version: https://www.matthewswong.com/id/blog/cors-configuration-nextjs-nestjs/
- English: https://www.matthewswong.com/en/blog/cors-configuration-nextjs-nestjs/
- Site index for agents: https://www.matthewswong.com/llms.txt
- Sitemap: https://www.matthewswong.com/sitemap.xml
- API description (OpenAPI): https://www.matthewswong.com/openapi.json
