CORS error muncul saat browser memblokir request lintas-origin karena server tidak mengirim header CORS yang sesuai atau tidak menangani preflight OPTIONS. Ini biasanya masalah konfigurasi di sisi server, bukan bug pada browser atau semata-mata kesalahan di front-end.
Di artikel ini, kamu akan belajar konsep dasar Same Origin Policy, alur preflight OPTIONS, header Access-Control-* yang penting, cara diagnosis lewat DevTools dan curl, serta contoh konfigurasi praktis untuk server populer agar API bisa diakses dengan aman dan benar.
Kenapa API Sering Terkena CORS Error Saat Dipanggil Front-End?

💻 Mulai Belajar Pemrograman
Belajar pemrograman di Dicoding Academy dan mulai perjalanan Anda sebagai developer profesional.
Daftar SekarangKalau tiap kali front-end manggil API selalu keblokir, biasanya browser menolak karena server tidak mengembalikan header CORS yang sesuai atau tidak merespons preflight OPTIONS. Tenang, ini umumnya masalah konfigurasi server, bukan bug pada browser.
Langkah pertama adalah diagnosis. Cek Origin, lihat error di Console, dan periksa respons OPTIONS di tab Network. Lalu, perbaiki header di server. Kemudian, bagaimana sih cara benerin konfigurasi header-nya di server? Kita mulai dari dasar konsep agar lebih paham sebelum masuk ke perbaikan praktis.
Mengerti Same Origin Policy dan Kapan Terjadi Masalah
Same Origin Policy adalah aturan keamanan browser yang hanya mengizinkan halaman mengakses resource dari origin yang sama. Origin ditentukan oleh tiga hal:
- Scheme (misalnya https),
- Host (misalnya api.example.com), dan
- Port (misalnya :443).
Jika salah satu beda, maka dianggap lintas-origin, misalnya dari https://app.example.com memanggil https://api.example.com atau dari http ke https. Di sinilah CORS dipakai untuk memberi izin terkontrol ke permintaan lintas-origin.
Browser membedakan antara simple request dan permintaan yang butuh preflight. Simple request biasanya memakai metode GET, HEAD, atau POST dengan header standar seperti Content-Type: application/x-www-form-urlencoded, multipart/form-data, atau text/plain.
Jika kamu memakai metode lain (misalnya PUT, DELETE), custom header, atau Content-Type non-standar, browser mengirim OPTIONS preflight dulu. Tujuannya untuk “tanya” ke server apakah permintaan lintas-origin tersebut diizinkan sebelum mengirim data sebenarnya.
Respons server yang benar minimal harus mengirim header berikut:
|
1 2 3 |
Access-Control-Allow-Origin: https://app.example.com Access-Control-Allow-Methods: GET, POST, OPTIONS Access-Control-Allow-Headers: Content-Type, Authorization |
Wildcard * pada Access-Control-Allow-Origin nyaman untuk publik API, tetapi berisiko jika digabung dengan credentials seperti cookies atau Authorization header. Untuk permintaan yang membawa identitas pengguna, selalu pakai origin spesifik, karena ini membatasi siapa saja yang boleh mengakses API dan memudahkanmu mendiagnosis CORS error di langkah berikutnya.
Mendiagnosis Penyebab CORS Error di Aplikasimu

Setelah paham same origin policy, langkah berikutnya adalah mendiagnosis kenapa permintaanmu diblokir. Mulai dari browser: buka DevTools, tab Console dan Network. Reproduksi aksi yang memicu request lalu catat pesan CORS error dan nilai header Origin yang dikirim.
Di tab Network, pilih request yang gagal dan lihat detailnya. Periksa header request seperti Origin, Access-Control-Request-Method, dan Access-Control-Request-Headers.
Lalu, cek respons server: ada tidak header Access-Control-Allow-Origin, Access-Control-Allow-Methods, dan Access-Control-Allow-Headers, serta status preflight OPTIONS.
Untuk memastikan masalah di sisi server, kamu bisa menyimulasikan preflight dengan curl:
|
1 2 3 4 |
curl -v -X OPTIONS https://api.example.com/resource \ -H "Origin: https://frontend.example.com" \ -H "Access-Control-Request-Method: POST" \ -H "Access-Control-Request-Headers: Content-Type, Authorization" |
Dari output ini, cocokkan apakah header Access-Control-Allow-* sudah muncul dan nilainya sesuai dengan request yang sebenarnya.
Konfigurasi Header Server untuk Mengizinkan Origin yang Tepat
Kalau sudah ketemu sumber masalahnya, kamu perlu mengatur CORS di server. Intinya: kamu mengontrol siapa yang boleh akses (origin), pakai method apa, dan header apa.
Lima header yang paling sering dipakai:
- Access-Control-Allow-Origin: origin yang diizinkan
- Access-Control-Allow-Methods: method yang diizinkan
- Access-Control-Allow-Headers: header yang diizinkan
- Access-Control-Allow-Credentials: izinkan cookies/credentials (true/false)
- Vary: Origin: wajib kalau Allow-Origin kamu dinamis
Contoh singkat Express middleware yang aman untuk satu origin:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
const allowedOrigin = 'https://app.example.com'; app.use((req, res, next) => { const origin = req.headers.origin; if (origin === allowedOrigin) { res.header('Access-Control-Allow-Origin', origin); res.header('Access-Control-Allow-Credentials', 'true'); res.header('Access-Control-Allow-Methods', 'GET,POST,PUT,DELETE,OPTIONS'); res.header('Access-Control-Allow-Headers', 'Content-Type, Authorization'); res.header('Vary', 'Origin'); } if (req.method === 'OPTIONS') { return res.sendStatus(204); } next(); }); |
Pola serupa bisa diterapkan di Nginx dengan directive add_header dan blok khusus untuk OPTIONS:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
map $http_origin $cors_origin { default ""; "~^https://app\.example\.com$" $http_origin; } server { location /api/ { if ($cors_origin = "") { return 403; } add_header Access-Control-Allow-Origin $cors_origin always; add_header Access-Control-Allow-Credentials "true" always; add_header Access-Control-Allow-Methods "GET,POST,PUT,DELETE,OPTIONS" always; add_header Access-Control-Allow-Headers "Content-Type, Authorization" always; add_header Vary "Origin" always; if ($request_method = OPTIONS) { return 204; } proxy_pass http://backend; } } |
Untuk Apache, aturan dasar di .htaccess bisa seperti ini:
|
1 2 3 4 5 6 7 8 9 |
<IfModule mod_headers.c> SetEnvIf Origin "^https://app\.example\.com$" ORIGIN_OK=$0 Header always set Access-Control-Allow-Origin "%{ORIGIN_OK}e" env=ORIGIN_OK Header always set Access-Control-Allow-Credentials "true" env=ORIGIN_OK Header always set Access-Control-Allow-Methods "GET,POST,PUT,DELETE,OPTIONS" env=ORIGIN_OK Header always set Access-Control-Allow-Headers "Content-Type, Authorization" env=ORIGIN_OK Header always set Vary "Origin" env=ORIGIN_OK </IfModule> |
|
1 2 3 4 5 6 7 8 9 |
<IfModule mod_headers.c> SetEnvIf Origin "^https://app\.example\.com$" ORIGIN_OK=$0 Header always set Access-Control-Allow-Origin "%{ORIGIN_OK}e" env=ORIGIN_OK Header always set Access-Control-Allow-Credentials "true" env=ORIGIN_OK Header always set Access-Control-Allow-Methods "GET,POST,PUT,DELETE,OPTIONS" env=ORIGIN_OK Header always set Access-Control-Allow-Headers "Content-Type, Authorization" env=ORIGIN_OK Header always set Vary "Origin" env=ORIGIN_OK </IfModule> |
Gunakan origin whitelist alih-alih *, batasi methods dan headers hanya yang benar-benar dipakai, dan pastikan OPTIONS tercatat di log untuk memantau preflight. Dengan begitu, konfigurasi CORS tetap fungsional tanpa membuka akses berlebihan, dan siap diuji di tahap berikutnya.
Tes Debug dan Best Practice Keamanan Setelah Perbaikan
Setelah ubah konfigurasi, lakukan verifikasi berikut:
-
Uji dari browser
-
-
- DevTools → Network.
- Pastikan OPTIONS dan request utama sama-sama sukses (status 2xx).
- Pastikan header Access-Control-Allow-* muncul dan nilainya sesuai.
-
-
Uji preflight dengan curl
|
1 2 3 4 |
curl -i \ -H "Origin: https://app-kamu.com" \ -H "Access-Control-Request-Method: GET" \ -X OPTIONS https://api-kamu.com/resource |
-
Kalau masih error, cek hal ini
-
-
- Origin di allowlist harus persis (termasuk http vs https, termasuk port).
- Header yang diminta browser harus ada di Access-Control-Allow-Headers.
- Method yang dipakai harus ada di Access-Control-Allow-Methods.
- Kalau CORS dinamis, pastikan ada Vary: Origin.
- Pastikan tidak ada middleware/reverse proxy yang menimpa header CORS yang sudah kamu set.
-
-
Best practice keamanan
-
- Hindari Access-Control-Allow-Origin: * untuk API yang butuh login/data sensitif.
- Jangan set Access-Control-Allow-Credentials: true kalau tidak benar-benar butuh cookies/session.
- Review ulang konfigurasi CORS setiap deploy production supaya tidak ada origin sementara/wildcard yang tertinggal.
Penutup
Dengan alur di atas, kamu bisa mendiagnosis penyebab utama CORS error, mengatur header yang tepat di server, dan menerapkan konfigurasi yang aman tanpa membuka akses berlebihan. Fokus pada tiga hal: origin yang tepat, preflight OPTIONS yang ditangani, dan pengujian ulang setelah perubahan. Hasilnya, front-end bisa mengakses API dengan lebih stabil dan aman.
