Saat melakukan integrasi REST API di React Native, pengembang sering kali menemui kendala di mana permintaan HTTP yang memerlukan autentikasi tiba-tiba menghasilkan respons 401 Unauthorized, meskipun token JWT atau kredensial yang dikirimkan sudah valid. Masalah ini umumnya dipicu oleh pengalihan HTTP (status kode 301, 302, 307, atau 308) yang memicu mekanisme keamanan native untuk menghapus header sensitif.
Akar Masalah: Native Credential Stripping
React Native tidak mengimplementasikan networking stack mandiri di JavaScript runtime (Hermes atau JavaScriptCore). Eksekusi fetch() atau XMLHttpRequest didelegasikan langsung ke lapisan native:
- Android: Menggunakan pustaka
OkHttp. - iOS: Menggunakan
NSURLSession.
Berdasarkan spesifikasi RFC 7235 (diperbarui dalam RFC 9110) serta standar implementasi keamanan browser dan HTTP client modern, klien dilarang meneruskan kredensial autentikasi (seperti header Authorization atau cookie sesi) ke origin yang berbeda selama proses redirect. Tujuannya adalah mencegah kebocoran token otorisasi ke server pihak ketiga.
Masalah muncul ketika pengalihan terjadi pada infrastruktur internal yang secara teknis dianggap "berbeda origin" oleh native layer, misalnya:
- Pengalihan protokol: dari
http://kehttps://. - Pengalihan subdomain: dari
api.example.comkeauth.example.comataueu-api.example.com. - Pengalihan port: dari
example.com:8080keexample.com:443.
Ketika kondisi ini terpenuhi, OkHttp dan NSURLSession secara otomatis melakukan header stripping pada Authorization sebelum mengeksekusi request berikutnya ke URL target.
Gejala Misterius 401 Unauthorized di Sisi JavaScript
Pelacakan bug ini sering kali membingungkan karena JavaScript networking polyfill di React Native membungkus seluruh siklus redirect secara transparan jika opsi default (redirect: 'follow') aktif.
Ketika request dieksekusi:
- Klien mengirim
GET /api/v1/profiledenganAuthorization: Bearer <token>. - Server merespons dengan status
301 Moved Permanentlydan headerLocation: https://api.example.com/api/v1/profile/(hanya perbedaan trailing slash). - Native stack mengikuti header
Location, namun menghapus headerAuthorizationkarena mendeteksi variasi rute atau canonical URL. - Server target menerima request kedua tanpa kredensial dan mengembalikan status
401 Unauthorized.
Di konsol JavaScript React Native, developer hanya melihat endpoint awal menghasilkan respons 401, sedangkan status 301 dan hop perantara tidak tercatat dalam log aplikasi tanpa bantuan network proxy eksternal.
Solusi 1: Eliminasi Redirect pada Rute Berautentikasi (Pendekatan Terbaik)
Solusi paling efisien dan aman adalah tidak membiarkan server mengirim respons pengalihan (3xx) pada endpoint yang memerlukan autentikasi. Frontend tidak perlu menulis kode tambahan jika backend dikonfigurasi dengan benar.
Penyebab umum redirect yang tidak perlu:
- Trailing slash mismatch: Server mengalihkan
/endpointke/endpoint/. Selaraskan URL pada client atau matikan strict-routing di backend router (misalnya Express, FastAPI, atau Laravel). - HTTP ke HTTPS: Pastikan base URL pada mobile client selalu mengarah ke skema HTTPS secara eksplisit.
- Reverse proxy / API Gateway: Jangan biarkan reverse proxy (Nginx, Cloudflare, Traefik) melakukan rewrite URL dengan status pengalihan 301/302 pada endpoint API internal.
Perhatian: Pengalihan metode POST/PUT dengan status 301 atau 302 dapat mengubah HTTP method menjadi GET secara otomatis menurut konvensi historis HTTP. Ini berisiko merusak payload data selain menghilangkan header autentikasi.
Solusi 2: Penanganan Redirect Manual dan Token Re-attaching
Jika modifikasi backend tidak memungkinkan (misalnya mengakses gateway pihak ketiga), pengalihan harus ditangani secara terkontrol di lapisan client. React Native mendukung penanganan respons redirect manual melalui inspeksi respons awal sebelum menembak URL target.
Lakukan validasi origin target terlebih dahulu sebelum menyematkan ulang header autentikasi demi mencegah token leak.
// client.js
const ALLOWED_ORIGINS = [
'https://api.example.com',
'https://internal-api.example.com'
];
function isSafeOrigin(targetUrl) {
try {
const parsed = new URL(targetUrl);
return ALLOWED_ORIGINS.includes(parsed.origin);
} catch {
return false;
}
}
export async function secureFetch(url, options = {}) {
const headers = { ...options.headers };
// Langkah 1: Minta manual redirect agar hop perantara tidak dieksekusi otomatis
const response = await fetch(url, {
...options,
headers,
redirect: 'manual'
});
// Periksa apakah server meminta redirect (301, 302, 307, 308)
// Catatan: Pada tipe 'opaqueredirect', status code mungkin 0 tergantung platform
const isRedirect = response.status >= 300 && response.status < 400;
const redirectLocation = response.headers.get('Location');
if (isRedirect && redirectLocation) {
const targetUrl = new URL(redirectLocation, url).toString();
// Verifikasi keamanan target sebelum menempelkan kredensial
if (!isSafeOrigin(targetUrl)) {
throw new Error(`Potensi kebocoran kredensial: Pengalihan ke origin tidak tepercaya (${targetUrl})`);
}
// Eksekusi ulang request ke target baru dengan header lengkap
return fetch(targetUrl, {
...options,
headers
});
}
return response;
}
Metode Debugging Native Network Hop
Untuk memastikan apakah request Anda mengalami drop header akibat redirect, jangan mengandalkan console.log() bawaan React Native. Gunakan alat inspeksi network langsung di level OS:
- Proxyman / Charles Proxy: Pasang sertifikat SSL di emulator/device untuk melihat seluruh aliran request termasuk status kode 3xx dan hilangnya header
Authorizationpada request kedua. - Flipper (Network Plugin): Pantau traffic network real-time yang mencatat setiap event dari native
OkHttpClientdanNSURLSession. - Logcat (Android): Tambahkan logging interceptor pada native code jika membangun modul native kustom untuk memverifikasi chain request yang dijalankan oleh OkHttp.
Ringkasan Tindakan
Langkah penanganan yang disarankan:
- Periksa base URL dan endpoint path. Hilangkan perbedaan trailing slash dan skema protokol.
- Konfigurasi web server/proxy agar langsung mengembalikan data tanpa hop pengalihan.
- Gunakan kontrol manual dan origin verification jika redirect antar-domain internal memang merupakan arsitektur yang tidak dapat dihindari.
Komentar
0 komentar
Masuk ke akun kamu untuk ikut berkomentar.
Belum ada komentar
Jadilah yang pertama ikut berdiskusi!