Server

401 Unauthorized — Arti Sebenarnya dan Cara Mengatasinya

Diperbarui 2026-08-31Baca ~9 menit

401 Unauthorized adalah salah satu kode status HTTP dengan penamaan terburuk. Ia tidak berarti Anda kekurangan izin — itu 403. Ia berarti server sama sekali tidak bisa memastikan Anda siapa, dan sedang mengundang Anda membuktikannya.

Perbedaan itu menentukan ke mana Anda harus melihat. 401 adalah masalah autentikasi: kredensial yang hilang, kedaluwarsa, salah format, atau ditolak. 403 adalah masalah otorisasi: identitas sudah ditetapkan dan memang tidak diizinkan. Memperbaiki 401 berarti memperbaiki cara kredensial dikirim; memperbaiki 403 berarti mengubah sebuah aturan.

Panduan ini membahas penyebab yang nyata, satu header wajib yang sering dilupakan, dan satu perilaku proxy yang diam-diam merusak autentikasi pada kode yang sudah sepenuhnya benar.

401 vs 403 dan kode tetangganya

Kode-kode ini dipakai secara tertukar di banyak API nyata, dan itulah justru alasan proses debug terasa membingungkan. Berikut arti yang seharusnya.

KodeArti sebenarnyaBisa diperbaiki pemanggil?
401 UnauthorizedBelum terautentikasi — identitas tak dikenal atau ditolakBisa — kirim kredensial yang valid
403 ForbiddenSudah terautentikasi, tapi tidak diizinkanTidak — pemilik harus mengubah aturan
407 Proxy Authentication RequiredProxy di tengah meminta kredensialBisa — autentikasi ke proxy
419 / 440 (non-standar)Sesi atau token CSRF kedaluwarsaBisa — muat ulang halaman atau ambil token baru
💡 Aturan praktis saat menulis API: kalau mengirim kredensial berbeda bisa mengubah hasilnya, kembalikan 401. Kalau tidak ada yang bisa dikirim pemanggil untuk membantu, kembalikan 403. Membedakannya sejak awal sangat menghemat waktu orang yang mendebug nanti.

Header yang semua orang lupakan

Spesifikasi HTTP menyebutkan dengan tegas: respons 401 wajib menyertakan header WWW-Authenticate yang memberi tahu klien cara berautentikasi. 401 tanpa header itu secara teknis adalah respons yang tidak valid.

Pada praktiknya banyak API mengembalikan 401 polos dengan body JSON tanpa header tersebut. Padahal browser dan HTTP client mengandalkannya untuk tahu langkah berikutnya — header inilah yang membuat browser memunculkan kotak nama pengguna dan kata sandi bawaan untuk basic auth.

Kalau Anda sedang membangun API, kirimkan: "WWW-Authenticate: Bearer" untuk autentikasi token, atau "WWW-Authenticate: Basic realm=..." untuk basic auth. Kalau Anda sedang mendebug API orang lain, ketiadaan header ini menandakan 401 tersebut ditulis manual di kode, bukan berasal dari lapisan auth standar — petunjuk berguna tentang di mana harus mencari.

Penyebab umum, dari yang paling sering

  • Token kedaluwarsa. Access token memang dirancang berumur pendek; solusinya memperbaruinya, bukan memperpanjang masa berlakunya.
  • API key salah atau tidak dikirim. Pastikan Anda memakai key untuk lingkungan yang benar — key staging ke endpoint produksi menghasilkan persis error ini.
  • Format header Authorization salah. Kapitalisasi "Bearer" yang keliru, spasi yang hilang, atau karakter baris baru yang ikut tersalin — semuanya gagal tanpa pesan jelas.
  • Basic auth salah konfigurasi di server. Path ke .htpasswd keliru, atau file kata sandi dibuat dengan format hash yang tidak bisa dibaca server.
  • Sesi kedaluwarsa. Pada website biasa ini hanyalah kasus "Anda telah keluar" yang normal, bukan bug.
  • Selisih jam server saat memakai JWT. Kalau jam berbeda melebihi toleransi token, token yang valid pun ditolak sebagai belum berlaku atau sudah kedaluwarsa. Periksa waktu di kedua mesin.
  • Header Authorization hilang di perjalanan — dibahas di bagian berikutnya, karena inilah yang paling banyak memakan waktu.

Jebakan: proxy yang menelan header Authorization

Bagian ini layak dapat bab sendiri karena kodenya benar, kredensialnya benar, tapi tetap mengembalikan 401.

Sebagian konfigurasi reverse proxy dan CGI membuang header Authorization sebelum sampai ke aplikasi. Apache dengan mod_cgi dan PHP-FPM adalah kasus klasik: kalau CGIPassAuth tidak diaktifkan atau header tidak diteruskan secara eksplisit, PHP tidak pernah melihatnya, dan setiap permintaan yang sudah terautentikasi tampak anonim.

Gejalanya khas: permintaan yang sama berhasil kalau dikirim langsung ke port aplikasi, tapi gagal lewat URL publik. Kalau Anda bisa mereproduksi perbedaan itu, pelakunya lapisan proxy, bukan kode autentikasi Anda.

Cara memastikan: catat header mentah yang benar-benar diterima aplikasi. Kalau Authorization tidak ada di sana padahal klien jelas mengirimnya, ada sesuatu di antaranya yang menghapusnya. Di Apache tambahkan "CGIPassAuth On"; di Nginx pastikan blok proxy_pass tidak menyaringnya; di hosting terkelola, tanyakan ke support apakah header itu diteruskan.

💡 Masalah sejenis juga menimpa header kustom. Kalau API jalan di lokal tapi gagal di produksi, bandingkan persis header yang diterima server di kedua tempat sebelum menyentuh logika autentikasi.

Periksa dengan urutan ini

  • Pastikan kredensialnya memang terkirim. Catat header di sisi klien, atau gunakan "curl -v" — flag -v mencetak apa yang dikirim.
  • Uji kredensial yang sama dengan curl langsung ke endpoint. Kalau curl berhasil sementara aplikasi Anda tidak, masalahnya ada di klien, bukan server.
  • Pastikan token belum kedaluwarsa. Kalau JWT, dekode dan baca klaim exp — jangan berasumsi, lihat nilainya.
  • Bandingkan jam server kalau melibatkan JWT. Selisih beberapa menit saja sudah membuat token valid ditolak.
  • Catat header yang benar-benar diterima server. Di sinilah header Authorization yang terpotong akan terlihat.
  • Periksa format yang diminta endpoint. Ada API yang mau "Bearer <token>", ada yang mau header "X-API-Key", ada yang lewat query parameter — mengirim nilai benar dengan cara salah tetap menghasilkan 401.
  • Baca body responsnya. Banyak API menyisipkan kode error spesifik di JSON yang membedakan kedaluwarsa, tidak valid, dan dicabut — tiga masalah berbeda dengan tiga solusi berbeda.

Kalau Anda yang membangun proteksinya

Ketika Anda yang mengeluarkan 401, beberapa keputusan berikut membuat hidup semua orang jauh lebih mudah.

Selalu kirim WWW-Authenticate seperti di atas. Ia wajib, dan itulah yang memberi tahu klien langkah selanjutnya.

Bedakan "kedaluwarsa" dari "tidak valid" di body. Token kedaluwarsa memberi tahu klien untuk memperbarui; token tidak valid memberi tahu klien untuk autentikasi ulang dari awal. Mengembalikan pesan kabur yang sama untuk keduanya memaksa klien menebak.

Jangan pakai 401 untuk menyembunyikan keberadaan sumber daya. Kalau ingin menyembunyikan ada atau tidaknya sesuatu, kembalikan 404 — itu praktik yang lazim. Sebuah 401 justru mengonfirmasi ada sesuatu di sana yang layak dicoba.

Batasi jumlah percobaan autentikasi yang gagal. Endpoint yang mengembalikan 401 persis menjadi sasaran alat penebak kredensial, dan endpoint login tanpa batas adalah undangan terbuka.

Pakai basic auth hanya di atas HTTPS. Basic auth mengirim kredensial dalam bentuk yang mudah didekode; lewat HTTP polos itu praktis sama dengan mengirim kata sandi terbuka.

Perlu melihat header yang benar-benar diterima server Anda?

Cloud VPS NVMe dengan akses root penuh — log sungguhan, atur sendiri proxy dan autentikasi. Mulai ฿150/bulan.

Pertanyaan yang Sering Diajukan

Apa beda 401 dan 403?

401 berarti server tidak tahu Anda siapa — autentikasi gagal atau tidak pernah diberikan, dan mengirim kredensial valid bisa memperbaikinya. 403 berarti Anda sudah dikenali tapi tetap tidak diizinkan, jadi mengganti kredensial tidak membantu. HTTP menamai keduanya terbalik: 401 sebenarnya "belum terautentikasi" dan 403 adalah "tidak berwenang".

API key saya benar tapi tetap 401. Kenapa?

Periksa tiga hal berurutan: apakah header benar-benar sampai ke server (catat header yang diterima), apakah Anda memakai skema yang diminta API (Bearer / X-API-Key / query parameter), dan apakah key itu milik lingkungan yang Anda panggil. Key staging ke endpoint produksi mengembalikan 401 tanpa petunjuk lain.

Kenapa autentikasi jalan di lokal tapi gagal di produksi?

Sangat sering karena reverse proxy atau lapisan CGI membuang header Authorization sebelum aplikasi melihatnya. Apache dengan PHP adalah kasus klasik dan butuh CGIPassAuth diaktifkan. Catat header mentah yang diterima aplikasi di kedua lingkungan lalu bandingkan — perbandingan itu biasanya menemukannya dalam hitungan menit.

Apakah 401 memengaruhi SEO?

Hanya kalau muncul di halaman yang seharusnya publik. Googlebot tidak bisa berautentikasi, jadi halaman di balik 401 tidak akan terindeks — dan itu perilaku yang benar untuk area privat. Masalah muncul saat aturan auth terlalu luas sampai menutupi halaman publik; pakai URL Inspection di Search Console untuk melihat apa yang benar-benar diterima Googlebot.