Ketika klien mengulang request otentikasi karena timeout atau error jaringan, API harus gagal secara konsisten tanpa menghasilkan efek samping ganda. CodeIgniter 4 dapat dicapai idempotensi ini dengan mengunci kontrak header/payload, menyimpan nonce, dan memastikan side effect otentikasi hanya dijalankan sekali.

Dalam artikel ini, kita langsung membahas strategi teknis: menegakkan header dan body konsisten, menyimpan nonce kecil untuk deduplikasi, menyiapkan middleware validasi, serta mengintegrasikan webhook/callback yang mengandalkan status side effect yang sudah terverifikasi.

1. Memahami Idempotensi untuk API Auth

Idempotensi berarti permintaan yang sama dapat dikirim ulang tanpa mengubah keadaan sistem lebih dari sekali. Untuk API otentikasi: jika klien mengirimkan kredensial dan server sudah mengeluarkan token, retry tidak boleh menyebabkan token baru yang berbeda atau perubahan status pengguna.

Key point:

  • Header/Body harus sama: Content-Type, X-Client-Request-Id, dan payload harus tidak dimodifikasi.
  • Jika server membuat side effect (misalnya mencatat login), itu hanya boleh terjadi setelah memastikan request belum diproses.

2. Menjaga Header dan Payload Konsisten

Terapkan kontrak yang jelas: klien wajib mengirimkan header tambahan seperti X-Request-Nonce atau X-Client-Request-Id yang dihasilkan di sisi klien pada setiap percobaan. Nilai ini menjadi kunci untuk membedakan retry dari request baru.

Gunakan middleware untuk memverifikasi hadirnya header tersebut dan menolak request yang hilang. Contohnya:

namespace Appilters;
use CodeIgniteriltersilterInterface;
use CodeIgniter
outer
outer;
use CodeIgniteriltersilterInterface;

class RequireNonce implements FilterInterface
{
    public function before(RequestInterface $request, $arguments = null)
    {
        if (! $request->hasHeader('X-Request-Nonce')) {
            return Services::response()
                ->setStatusCode(422)
                ->setJSON(['error' => 'Nonce header is required']);
        }
    }

    public function after(RequestInterface $request, ResponseInterface $response, $arguments = null)
    {
        // no-op
    }
}

Pastikan middleware ini dipasang hanya pada rute otentikasi. Header lain seperti Idempotency-Key dapat digunakan jika klien dapat menjamin keunikannya.

3. Menyimpan Nonce untuk Deduplikasi

Setelah header nonce valid, simpan nilai tersebut dengan status singkat (misalnya 5 menit) menggunakan cache atau storage cepat seperti Redis. Tujuannya mendeteksi retry yang sama.

Contoh implementasi menggunakan cache Redis di controller:

public function authenticate()
{
    $nonce = $this->request->getHeaderLine('X-Request-Nonce');

    if (cache('auth_nonce_' . $nonce)) {
        return $this->response->setStatusCode(200)
            ->setJSON(['message' => 'Request sudah diproses', 'status' => 'ok']);
    }

    $credentials = $this->request->getJSON();
    if (! $this->validateCredentials($credentials)) {
        return $this->response->setStatusCode(401)->setJSON(['error' => 'Otentikasi gagal']);
    }

    cache()->save('auth_nonce_' . $nonce, true, 300);
    $token = $this->issueToken($credentials);

    return $this->response->setJSON(['token' => $token]);
}

Cache/Redis hanya menyimpan flag bahwa nonce sudah digunakan. Pastikan cache memiliki TTL yang mencerminkan durasi retry yang masuk akal.

4. Middleware dan Pola Side Effect

Middleware perlu memastikan status side effect tidak dioleskan dua kali. Misalnya, pencatatan login atau pemicu email welcome hanya boleh dijalankan setelah nonce disimpan dan token terbentuk.

Urutan aman:

  1. Validasi nonce dan credentials.
  2. Simpan nonce sebelum side effect.
  3. Generate token.
  4. Jalankan side effect yang bukan idempotent, seperti log event, setelah memastikan nonce tidak duplikat.

Menggunakan event dispatcher membantu memisahkan logika token dan side effect. Pastikan handler side effect memeriksa ulang bahwa token belum pernah diproses dengan nonce yang sama.

5. Integrasi Webhook/Callback dengan Status Side Effect

Jika otentikasi memicu webhook atau callback (misalnya verifikasi dua langkah), sistem pihak ketiga harus menerima status pasti tentang apakah side effect sudah terjadi. Tanpa idempotensi, webhook bisa menyebabkan notifikasi ganda.

Pola aman:

  • Webhook menerima payload yang memuat nonce dan status processed/duplicate.
  • Server API secara eksplisit mengembalikan status yang sama setiap kali retry terjadi.

Contoh respons ketika nonce sudah diproses:

HTTP/1.1 200 OK
Content-Type: application/json

{
  "status": "duplicate",
  "message": "Token sudah diberikan sebelumnya",
  "nonce": "abc123"
}

Webhook dapat menggunakan informasi ini untuk menghindari trigger ulang dan mendokumentasikan bahwa request kedua tidak membalikkan side effect.

6. Debugging dan Trade-off

Masalah umum: tidak membersihkan nonce kadaluarsa menyebabkan false positive. Pastikan TTL cache cukup panjang untuk meng-cover retry normal tapi tidak terlalu lama agar tidak menolak request baru.

Trade-off: pendekatan ini menambah ketergantungan pada storage tambahan dan logika cache. Namun, menjaga idempotensi otentikasi jauh lebih penting daripada overhead kecil tersebut.

Gunakan logging saat nonce terdeteksi duplikat agar developer bisa menelusuri retry bermasalah dan memastikan klien mematuhi kontrak header.

Kesimpulan

Untuk menjaga idempotensi API Auth di CodeIgniter 4, kombinasikan validasi header, penyimpanan nonce singkat, middleware khusus, dan respons status konsisten. Dengan pendekatan ini, retry klien tidak akan menghasilkan efek samping ganda atau inkonsistensi token. Pastikan juga integrasi webhook membaca status side effect agar ekosistem luar tetap sinkron.