Token exchange & refresh

Menukar code

Form-encoded, bukan JSON. Code berumur 5 menit dan sekali pakai; redirect_uri dicocokkan literal dengan yang dikirim saat authorize, sesuai RFC 6749 §4.1.3.

Client public mengirim code_verifier. Client confidential menambahkan client_secret atau memakai HTTP Basic.

Refresh dan rotasi

curl -X POST https://api-sandbox.tracive.id/v1/oauth/token \
  -H 'Content-Type: application/x-www-form-urlencoded' \
  -d grant_type=refresh_token \
  -d refresh_token=<refresh token terakhir> \
  -d client_id=trcvc_…

Setiap refresh merotasi tokennya: respons membawa refresh token baru, dan yang lama pensiun. Simpan yang baru sebelum melanjutkan.

Access token1 jam.
Refresh tokenKedaluwarsa setelah 90 hari tidak dipakai.
Jendela grace60 detik setelah rotasi.
Jendela grace ada untuk jawaban yang hilang di jalan. Kalau rotasi berhasil di server tapi responsnya tidak sampai, mengulang dengan token lama dalam 60 detik akan dijawab dengan token baru yang sama, bukan dianggap pencurian.

Deteksi penggunaan ulang

Di luar jendela grace, menyodorkan refresh token yang sudah pensiun membuat seluruh grant dicabut, bukan sekadar panggilan itu yang gagal. Webhook grant.revoked dikirim, dan pengguna harus memberi izin lagi.

Ini perilaku yang benar untuk token yang bocor, tapi juga cara paling mudah merusak integrasi sendiri. Dua sumber masalah yang sering:

  • · Menyimpan refresh token di dua tempat dan menyegarkan dari keduanya. Satu proses akan memakai yang sudah pensiun.
  • · Beberapa panggilan bersamaan yang semuanya kena 401 lalu semuanya menyegarkan. SDK menyerialkannya jadi satu; kalau Anda memanggil HTTP langsung, Anda yang harus.

Mencabut

POST /v1/oauth/revoke, RFC 7009. Mencabut refresh token mengakhiri grant dan setiap access token di bawahnya. Mencabut token yang sudah dicabut tetap dijawab sukses; itu idempoten menurut spesifikasinya.

Bentuk error di sini berbeda

Endpoint token dan revoke menjawab dengan bentuk datar RFC 6749 §5.2, bukan amplop yang dipakai endpoint data:

{ "error": "invalid_grant", "error_description": "PKCE verification failed." }

Bukan kelalaian: setiap klien OAuth, termasuk pustaka pihak ketiga, membaca error sebagai string di sini.