-
Notifications
You must be signed in to change notification settings - Fork 0
How It Works
The API reproduces the same login handshake the Free Fire client performs against Garena, then returns the resulting session token as JSON.
┌──────────────────────────────────────────────┐
GET /v1/auth ──►│ 1. Validate API key (master key or DB lookup) │
└───────────────────────┬──────────────────────┘
▼
┌───────────────────────────────────────────────────────────┐
│ 2. Garena OAuth guest token grant │
│ POST 100067.connect.garena.com/oauth/guest/token/grant │
│ → access_token, open_id │
└───────────────────────────┬───────────────────────────────┘
▼
┌───────────────────────────────────────────────────────────┐
│ 3. Build Protobuf LoginReq(open_id, login_token=access) │
│ → serialize → AES‑128‑CBC encrypt │
└───────────────────────────┬───────────────────────────────┘
▼
┌───────────────────────────────────────────────────────────┐
│ 4. POST encrypted payload to {MAJOR_LOGIN_URL}/MajorLogin │
│ headers include ReleaseVersion, octet-stream body │
└───────────────────────────┬───────────────────────────────┘
▼
┌───────────────────────────────────────────────────────────┐
│ 5. Parse Protobuf LoginRes → JSON → reorder + clean │
└───────────────────────────┬───────────────────────────────┘
▼
JSON response to client
The incoming apikey is accepted if it equals the master VALID_API_KEY, or if it exists in the api_keys table with status='active' and an expires_at in the future. See API Reference.
A form‑encoded POST is sent to:
https://100067.connect.garena.com/oauth/guest/token/grant
with the guest uid + password, a fixed client_id / client_secret, response_type=token and client_type=2. The response yields:
access_tokenopen_id
These identify the guest session for the next step.
A LoginReq Protobuf message is populated:
| Field | Value |
|---|---|
open_id |
from step 2 |
open_id_type |
"4" |
login_token |
the access_token from step 2 |
orign_platform_type |
"4" |
The serialized message is padded (PKCS‑style) and encrypted with AES‑128 in CBC mode using the built‑in MAIN_KEY / MAIN_IV.
The encrypted bytes are sent as application/octet-stream to {MAJOR_LOGIN_URL}/MajorLogin with headers including:
| Header | Value |
|---|---|
User-Agent |
Android Dalvik UA string |
Content-Type |
application/octet-stream |
X-Unity-Version |
2018.4.11f1 |
X-GA |
v1 1 |
ReleaseVersion |
from config.json (e.g. OB53) |
MAJOR_LOGIN_URL and ReleaseVersion come from the remote config.json, so they can be updated as the game changes without a code change.
The binary response is parsed back into the LoginRes Protobuf message and converted to JSON. The app:
- removes
ttlandanoUrl, - re‑orders the remaining fields into a stable shape,
- injects the
accessTokenfrom step 2,
then returns the final JSON described in API Reference.
The .proto definitions are embedded directly in app.py as a serialized descriptor. The relevant messages are:
-
LoginReq—open_id,open_id_type,login_token,orign_platform_type -
LoginRes—account_id, region fields,token,server_url,blacklist(ban info),queue_info, and more -
BlacklistInfoRes+BanReasonenum — used for ban/blacklist details
The handshake (get_jwt) is fully async (httpx.AsyncClient) and run per‑request via asyncio.run. In production, Gunicorn's gevent workers handle many concurrent connections — see Deployment.
TSun FF JWT API · MIT License · Built by 𝙎ค૯𝙀𝘿✘🫀 for TSun FreeFire × Script Kittens