Sharing hasil analisa aplikasi TokopediaPro (Android v44.5.1). Tujuannya satu: memahami cara aplikasi berkomunikasi dengan server-nya, lalu membangun ulang SDK client-nya dengan TypeScript supaya operasi seperti login, search, dan cart bisa dijalankan lewat kode.
Catatan: murni untuk riset dan edukasi. Gunakan akun sendiri, hormati ToS Tokopedia/TikTok, dan jangan push token/kredensial ke git publik.
Alat
- JADX — decompile
base.apk, baca logika signing
- HTTP Toolkit — capture traffic HTTP/HTTPS (workflow
mcp-http-trace)
- Frida — bridge ke fungsi signing native
- Node.js + TypeScript — implementasi SDK
Dua Backend Berbeda
Traffic aplikasi tidak menuju satu server saja. Ada dua pola:
| Bagian | Backend | Protokol |
| Login, OTP, Profil, Toko | gql.tokopedia.com | GraphQL (/ttgraphql/*) |
| Search & suggest | search.tiktokv.com | REST (x-www-form) |
| Detail produk (PDP), Cart | oec.tokopediax.com | REST (JSON) |
Sebagian masih memakai infrastruktur lama Tokopedia (GraphQL), sebagian sudah pindah ke infrastruktur TikTok/ByteDance. Konsekuensinya: skema signing tiap backend berbeda.
Signing Header
Ini bagian inti. Server menolak request jika header tanda tangan salah. Ada dua jenis.
1. TKPDROID — bisa direproduksi
Skema lama Tokopedia, ditemukan di class TkpdAuthInterceptorTTNet. Isinya HMAC-SHA1 biasa:
canonical = METHOD + "\n"
+ md5(body) + "\n"
+ "application/json" + "\n"
+ Date + "\n"
+ (POST: path | GET: query string)
sig = base64( HmacSHA1(canonical, "Akfiew834298POinv") )
header = "Authorization: TKPDROID AndroidApps:" + sig
Secret (Akfiew834298POinv) disamarkan sebagai array angka ASCII di konstanta obfuscated, dirakit ulang saat runtime. Setelah ketemu, skema ini ditulis ulang di Node.js pakai modul crypto bawaan — tanpa perlu aplikasi. Ini yang membuat login dan GraphQL jalan penuh dari TypeScript.
2. x-gorgon / x-argus / x-ladon / x-khronos — tidak bisa direproduksi
Keluarga header ByteDance. Diproduksi di library native libmsaoidsec.so lewat:
ms.bd.o.g2.frameSign(String url, int type) -> Map<String,String>
Logikanya di kode native yang di-obfuscate, tidak bisa ditiru di JS murni. Pendekatannya: bukan ditiru, tapi dipinjam. Bridge kecil berbasis Frida menempel ke aplikasi asli di device, memanggil frameSign langsung, lalu mengekspos hasilnya lewat HTTP server lokal. SDK menembak ke situ tiap butuh tanda tangan.
Jika sudah punya access token hasil capture dari device asli, sebagian endpoint bisa jalan hanya bermodal token. Bridge Frida baru wajib untuk login fresh atau endpoint REST yang diproteksi.
Alur Login
Login email berlapis:
register_check -> cek email/HP terdaftar atau tidak
generate_key -> minta RSA public key dari server
RSA encrypt password -> password dienkripsi (PKCS#1 v1.5), tidak dikirim polos
login_email_v2 -> kirim username + password terenkripsi
└─ jika sq_check==true (2FA):
OTPModeList -> OTPRequestV2 -> OTPValidateV2 -> login_after_sq
Password tidak pernah dikirim mentah — selalu dienkripsi dulu dengan public key yang diminta per sesi.
Struktur SDK di TypeScript
Prinsipnya: pisahkan tiap lapisan supaya bagian yang rumit (signing) tidak mencemari logika fitur.
TokopediaClient (facade)
├── HttpClient -> transport low-level GraphQL
├── RestClient -> transport low-level REST (oec + search)
├── GqlClient -> perakit envelope GraphQL
├── Signer -> abstraksi tanda tangan (swappable)
│ ├── TkpdSigner -> HMAC-SHA1 (murni JS)
│ ├── HttpSigner -> ke bridge Frida
│ └── NoopSigner -> mode token, tanpa tanda tangan
└── modules/
├── auth -> login, OTP
├── profile -> profil + data toko
├── product -> search + detail produk
├── cart -> keranjang
└── checkout / transaction (TODO)
Kunci desainnya di abstraksi Signer. Signing adalah bagian paling variatif, jadi dibuat pluggable:
- Pakai token capture saja ->
NoopSigner.
- Login sungguhan ->
HttpSigner ke bridge Frida.
- Cuma butuh GraphQL ->
TkpdSigner, murni JS.
Modul (auth, cart, dll) tidak perlu tahu soal tanda tangan. Mereka memanggil, Signer yang mengurus. Pemakaiannya:
const client = new TokopediaClient({
config: defaultConfig(),
signer: new HttpSigner(process.env.TKPD_SIGNER_URL),
sessionStore: new SessionStore(".session.json"),
});
await client.restoreSession();
const { profile, shop } = await client.profile.me();
const hits = await client.product.search({ keyword: "dell" });
const detail = await client.product.detail({ productId: hits.hits[0].product_id });
await client.cart.add({
productId: hits.hits[0].product_id,
skuId: detail.data?.skus?.[0].id ?? "0",
sellerId: detail.data?.product?.id ?? "0",
quantity: 1,
});
Di balik pemanggilan sesederhana itu, SDK mengurus belasan header, MD5 body, RSA, dan tanda tangan native.
Status
| Fitur | Status |
| Login (email) + OTP/2FA | jalan |
| Profil & Toko | jalan |
| Search + suggest | jalan |
| Detail produk (PDP) | jalan |
| Tambah / lihat / hapus cart | jalan |
| Checkout / bayar | belum di-capture |
| Riwayat transaksi | belum di-capture |
Sisanya tinggal capture aksinya sekali lewat HTTP Toolkit, lalu tempel query/path ke modul yang sudah disiapkan.
Ringkasan
- Aplikasi besar sering mencampur banyak backend — jangan asumsikan satu server dengan satu aturan.
- Tidak semua signing harus ditiru. Yang di native lebih efisien dipinjam via Frida daripada dipaksa reimplementasi.
- Arsitektur berlapis plus abstraksi Signer memisahkan bagian rumit dari logika fitur, sehingga menambah endpoint baru jadi murah.
Terbuka untuk diskusi soal detail signing atau pengalaman menganalisa aplikasi sejenis.
Catatan: proyek edukasi. Token, kredensial, dan file capture jangan pernah masuk ke git publik.