Masalah login ganda dengan token yang saling menimpa sering kali bermula dari cache yang tidak ter-invalidate dengan benar. Pada kasus produksi ini, pengguna mendapatkan token lama sekaligus baru karena otentikasi membaca status sesudahnya dari cache Redis yang stale. Artikel ini langsung menjawab kenapa token ganda terjadi, bagaimana mengidentifikasi sumbernya, dan langkah teknis untuk memperbaiki dan mencegah ulang.
Gejala awal dan observasi pemantauan
Gejala pertama adalah laporan dari tim support: sesi login terkadang menolak validasi token baru dan user harus logout manual. Pemantauan di Grafana menunjukkan spike latency pada endpoint /api/login dan peningkatan cache hit ratio yang abnormal. Logging tambahan di middleware otentikasi memperlihatkan token baru ditulis ke cache lalu pada request berikutnya framework membaca token lama akibat cache stale.
- Token baru dibuat dan disimpan di Redis dengan key bertipe
login-token-user:{id}. - Endpoint protected mengandalkan cache daripada database untuk mempercepat validasi.
- Jumlah cache set di Redis menurun sebelum ada cache invalidation eksplisit, sehingga token lama masih dibaca.
Kasus semacam ini berisiko tinggi karena mengganggu user experience dan membuka celah keamanan jika token lama tidak kedaluwarsa dengan cepat.
Investigasi log, query, dan metrik
Penyelidikan dimulai dengan menambahkan log detail di middleware otentikasi. Dua catatan penting: waktu pembuatan token tercatat, dan semua cache read/write disertai trace ID request. Dari sana ditemukan pola bahwa Cache::remember digunakan tanpa invalidasi eksplisit setelah login sukses.
Query database menunjukkan update terakhir ke tabel user_sessions sukses, namun middleware tidak memanggil Cache::forget sebelum menulis token baru. Selain itu, metric Redis memperlihatkan latency meningkat karena key eviction yang tidak konsisten — indikator queue worker yang menangani invalidasi ter-stuck.
Selama investigasi, kami menjalankan Redis MONITOR untuk melihat sequence berikut:
*1
$5
SET
$23
login-token-user:42
$36
"eyJhbGciOi..."
*3
$7
GET
$23
login-token-user:42
Key dibacakan lagi sebelum operasi invalidasi selesai, menandakan queue worker belum memproses job invalidasi karena konfigurasi queue menggunakan driver sync di environment staging/production yang bermasalah saat beban tinggi.
Metric tambahan
- Redis keyspace hits tinggi namun miss rendah, menunjukkan cache terlalu dipercaya.
- Queue latency meningkat menjelang jam sibuk karena job invalidasi diantar dalam batch berukuran besar.
Menemukan akar masalah cache stale Redis dan queue
Root cause utama adalah konfigurasi cache dan queue yang tidak sinkron: worker invalidasi token dijadwalkan melalui queue tetapi driver Redis/timestamp tidak menghapus key lama tepat waktu. Ini terjadi karena queue worker berjalan di server berbeda tanpa cache prefix yang sama, lalu key invalidasi tidak pernah matching.
Sementara itu, middleware otentikasi tidak memeriksa apakah token yang di-cache sudah kadaluarsa dengan membandingkan timestamp di database atau header. Cache lifetime ditentukan hanya dalam konfigurasi cache.php tanpa memperhatikan lifecycle token.
Langkah perbaikan dan mitigasi
Perbaikan dilakukan bertahap, dimulai dari invalidasi cache dan memperkuat middleware:
- Invalidasi cache langsung di login:
Cache::forget('login-token-user:' . $user->id); $token = $this->tokenService->createToken($user); Cache::put('login-token-user:' . $user->id, $token, now()->addMinutes(15)); return response()->json(compact('token')); - Queue worker: ubah driver queue menjadi
redisdenganretry_aftersesuai waktu proses, dan tambahkan middleware yang mengecek timestamp token sebelum dijadikan valid. - Middleware otentikasi: tambahkan logika validasi ganda dengan membandingkan
token_iatdari payload dengan timestamp cache agar token lama langsung ditolak walau masih ada di cache. - Cache prefix: pastikan konfigurasi redis memiliki
'prefix' => env('REDIS_PREFIX', 'laravel_cache:')seragam antara app dan worker.
Setelah perubahan config, jalankan php artisan config:cache dan php artisan queue:restart untuk memastikan worker menggunakan versi terbaru.
Pengujian regresi dan rollback cepat
Regresi diuji melalui skenario integrasi:
- Simulasikan login multi-device untuk satu user memastikan cache invalidated dan token lama tidak bisa digunakan.
- Gunakan Laravel Dusk atau API testing untuk mengeksekusi login, lalu capture token dan ujikan di endpoint lain.
Jika perubahan menyebabkan masalah baru, rollback cepat dilakukan dengan rollback deploy (biasanya git revert atau forge deployment) lalu restart queue worker. Buat checklist validasi sebelum rollback seperti memonitor error rate dan login success rate.
Tips monitoring dan pencegahan regresi
Untuk memantau regresi serupa, tambahkan metric berikut:
- Token refresh ratio: bandingkan jumlah token baru yang di-issue dengan jumlah login untuk mendeteksi kebocoran tidak sah.
- Cache invalidation latency: ukur delay antara penulisan token dan key invalidated.
- Redis evicted keys dan queue failure rate sebagai indikator overload.
Gunakan alerting jika ratio token ganda naik di atas ambang wajar. Tambahkan automation test yang memperhatikan cache state untuk setiap release dan dokumentasikan flow invalidasi agar pengembang lain memahami dependency cache/queue.
Dengan kombinasi invalidasi eksplisit, middleware yang memperkuat validasi token, dan monitoring targeted, regresi token login ganda akibat cache stale dapat dicegah sekaligus ditangani secara cepat di produksi.
Komentar
0 komentar
Masuk ke akun kamu untuk ikut berkomentar.
Belum ada komentar
Jadilah yang pertama ikut berdiskusi!