Generate valid g-auth / g-device-id headers for Golike gateway API
Project description
golike-gauth
Generate valid g-auth / g-device-id headers for the Golike gateway API.
Repo: https://github.com/deno4908/golike-gauth
Install
pip install golike-gauth
# optional: HTTP helper (requests)
pip install "golike-gauth[requests]"
# install from GitHub
pip install git+https://github.com/deno4908/golike-gauth.git
Quick start
Chỉ cần token (khuyến dùng)
Hầu hết trường hợp chỉ nhập JWT. Các tham số còn lại lấy từ API (User-Agent mobile).
from golike_gauth import GolikeAuth
auth = GolikeAuth.from_token("eyJ...") # chỉ token
print(auth.user_id) # JWT sub
print(auth.username) # /users/me
print(auth.device_id) # UUID tự sinh
print(auth.signing_key) # = data.firebase_id (app web cũng set như vậy)
print(auth.profile) # raw /users/me
Flow from_token làm gì?
| Bước | Nguồn | Kết quả |
|---|---|---|
| 1 | Decode JWT | user_id = sub |
| 2 | GET /users/me (UA mobile Android) |
username, coin, firebase_id, … |
| 3 | signing_key |
mặc định = data.firebase_id (trùng store.state.signing_key trên app) |
| 4 | device_id |
UUID v4 (tự tạo, nên lưu lại) |
| 5 | (tuỳ chọn) verify=True |
POST /security/echo kiểm tra key decrypt được |
# verify echo (mac dinh True) — fail neu key sai
auth = GolikeAuth.from_token("eyJ...", verify=True)
# bo qua verify echo
auth = GolikeAuth.from_token("eyJ...", verify=False)
# hiếm khi firebase_id != store key → truyền tay:
auth = GolikeAuth.from_token(
"eyJ...",
signing_key="cxbbf6td1EXc...", # store.state.signing_key
)
Lấy token từ đâu?
Trên https://app.golike.net (đã login, F12 → Network):
- Request bất kỳ → header
Authorization: Bearer eyJ... - Hoặc Application / Local Storage / vuex (field
token)
signing_key thường không cần dán: app gán store.signing_key = me.firebase_id.
Ví dụ: lấy job Facebook chỉ với token
from golike_gauth import GolikeAuth
auth = GolikeAuth.from_token("eyJ...", verify=False)
# dam bao dung firebase_id
if auth.profile.get("firebase_id"):
auth.signing_key = auth.profile["firebase_id"]
# list account FB tren Golike
accs = auth.get("/fb-account?limit=200").json().get("data") or []
fb_id = accs[0]["fb_id"]
r = auth.get(
f"/advertising/publishers/get-jobs-2026"
f"?fb_id={fb_id}&server=sv2&high_job=1&low_job=1"
)
print(r.status_code, r.json())
Script mẫu trong workspace: test_fb_jobs.py (chỉ hỏi token).
Thủ công (5 trường)
from golike_gauth import GolikeAuth
auth = GolikeAuth(
token="eyJ...", # JWT Bearer
signing_key="...", # = firebase_id hoac store.state.signing_key
user_id=123456, # JWT sub
username="your_username",
device_id="32484704-8a4e-4909-9d42-866773b321d6", # nên giữ cố định
)
Lib dùng được với mọi path gateway. Chỉ cần đúng method + path + body/query như browser.
Cách dùng chung (khuyến nghị)
# GET — không body, params = query string
r = auth.get("/path/to/api", params={"key": "value"})
print(r.status_code, r.json())
# POST — có JSON body (g-auth ký đúng body compact, không space)
r = auth.post("/path/to/api", json={"a": 1, "b": "x"})
print(r.status_code, r.json())
# method bất kỳ
r = auth.request("PUT", "/path/to/api", json={...})
r = auth.request("DELETE", "/path/to/api")
Ví dụ thật theo platform
Instagram — lấy job (GET)
r = auth.get(
"/advertising/publishers/instagram/jobs",
params={
"instagram_account_id": "966624",
"data": "null",
},
)
# hoặc helper:
r = auth.get_instagram_job("966624")
print(r.json())
Instagram — skip job (POST, không phải GET!)
r = auth.post(
"/advertising/publishers/instagram/skip-jobs",
json={
"ads_id": 620978,
"object_id": "6155111723",
"account_id": 966624,
"type": "follow", # follow | like | comment | ...
},
)
# hoặc helper:
r = auth.skip_instagram_job(
ads_id=620978,
object_id="6155111723",
account_id=966624,
type="follow",
)
print(r.json())
Instagram — complete job (POST)
r = auth.post(
"/advertising/publishers/instagram/complete-jobs",
json={
"instagram_users_advertising_id": 620978,
"instagram_account_id": 966624,
"async": True,
"data": None,
},
)
# hoặc helper:
r = auth.complete_instagram_job(
instagram_users_advertising_id=620978,
instagram_account_id=966624,
)
print(r.json())
Twitter / X — lấy job (GET)
Tương đương curl:
GET /api/advertising/publishers/twitter/jobs?account_id=97445
r = auth.get(
"/advertising/publishers/twitter/jobs",
params={"account_id": "97445"},
)
print(r.status_code, r.json())
TikTok / Facebook / … (cùng pattern)
# GET jobs (query tùy platform — copy từ Network tab browser)
r = auth.get(
"/advertising/publishers/tiktok/jobs",
params={"account_id": "123"}, # hoặc param khác tùy API
)
# POST skip / complete — luôn dùng auth.post(..., json={...})
r = auth.post(
"/advertising/publishers/tiktok/skip-jobs",
json={...}, # body copy từ Network tab
)
Users / endpoint khác
r = auth.get("/users/me")
r = auth.post("/some/path", json={"foo": "bar"})
Sai thường gặp
# ❌ SAI: auth.post() đã gọi API, không phải headers
# ❌ SAI: skip-jobs dùng GET → 405
response = requests.get(
"https://gateway.golike.net/api/advertising/publishers/instagram/skip-jobs",
headers=auth.post("/advertising/publishers/instagram/skip-jobs", json={...}),
)
# ✅ ĐÚNG
response = auth.post(
"/advertising/publishers/instagram/skip-jobs",
json={
"ads_id": 620978,
"object_id": "6155111723",
"account_id": 966624,
"type": "follow",
},
)
print(response.json())
Nếu tự dùng requests, method + body bytes phải khớp lúc ký:
import json
import requests
body = {
"ads_id": 620978,
"object_id": "6155111723",
"account_id": 966624,
"type": "follow",
}
raw = json.dumps(body, separators=(",", ":"), ensure_ascii=False) # không space
headers = auth.headers(
"POST",
"/advertising/publishers/instagram/skip-jobs",
body=raw,
)
response = requests.post(
"https://gateway.golike.net/api/advertising/publishers/instagram/skip-jobs",
headers=headers,
data=raw.encode("utf-8"),
)
Headers only / low-level
from golike_gauth import generate_g_auth, generate_device_id, decode_g_auth
# headers: method/path/body phải trùng request thật
headers = auth.headers(
"GET",
"/advertising/publishers/twitter/jobs",
body="", # GET không body
)
g_auth = generate_g_auth(
method="GET",
path="/advertising/publishers/twitter/jobs",
body="",
signing_key="...",
device_id=generate_device_id(),
user_id=123456,
)
print(decode_g_auth(g_auth, "..."))
Method cheatsheet
| API | Method | Params / Body |
|---|---|---|
/advertising/publishers/instagram/jobs |
GET | query: instagram_account_id, data |
/advertising/publishers/instagram/skip-jobs |
POST | JSON: {ads_id, object_id, account_id, type} |
/advertising/publishers/instagram/complete-jobs |
POST | JSON: {instagram_users_advertising_id, instagram_account_id, async, data, ...} |
/advertising/publishers/twitter/jobs |
GET | query: account_id |
/users/me |
GET | — |
| path khác | copy từ browser Network | đúng method + body như browser |
Quy tắc:
- GET →
auth.get(path, params=...)— body ký ="" - POST →
auth.post(path, json=...)— body ký = JSON compact - 405 = sai method (vd. GET
skip-jobs) - g-auth tạo mới mỗi request, khớp method + path + body
- Path truyền vào không cần
/apiprefix (authtự thêm base.../api)
Where to get signing_key
On https://app.golike.net (logged in), DevTools console:
document.querySelector('#app').__vue__.$store.state.signing_key
This value may differ from
data.firebase_idin/users/me. Always use the store key the browser actually signs with.
CLI
golike-gauth \
--token eyJ... \
--signing-key ... \
--user-id 123456 \
--username your_username \
--call --ig-account-id YOUR_IG_ACCOUNT_ID
Notes
g-authmust be regenerated for every request (binds method + path + body hash + timestamp).- GET requests sign body as empty string
"". - Path signed is pathname only, e.g.
/api/advertising/publishers/instagram/jobs.
Development
git clone https://github.com/deno4908/golike-gauth.git
cd golike-gauth
python -m pip install -e ".[dev,requests]"
Build & publish (PyPI)
python -m pip install -U build twine
python -m build
python -m twine upload dist/*
Contributing
Issues and PRs: https://github.com/deno4908/golike-gauth/issues
License
Phân tích mã hóa / giải mã g-auth (Golike Gateway)
Tài liệu này mô tả cách app web Golike tạo header g-auth cho mỗi request tới gateway.golike.net, và cách server (hoặc client debug) giải mã token đó.
Nguồn reverse: bundle index-68ef440b.js (các hàm H_, q_, Mg, M_, j_, Jd, aA, bu).
1. Vai trò của g-auth
g-auth là request-binding token: mỗi request HTTP mang một token mới, gắn với:
| Trường payload | Ý nghĩa |
|---|---|
n |
HTTP method (GET / POST / …) |
k |
Pathname API (không có query) |
q |
SHA-256 hex của body |
d |
g-device-id (UUID) |
u |
user_id |
t |
timestamp client (ms) |
x |
nonce ngẫu nhiên |
r |
digest ngắn chống giả mạo thô |
Token được mã hóa AES-GCM bằng khóa dẫn xuất từ signing_key của user. Server giải mã → kiểm tra method/path/body/device/user/time → cho phép request.
g-authkhông tái sử dụng được giữa các request (path/body/time khác nhau, và có nonce).
2. Các header liên quan
Ngoài JWT Authorization: Bearer …, client còn gửi:
| Header | Nguồn / công thức |
|---|---|
g-auth |
AES-GCM token (mục 4–5) |
g-device-id |
UUID v4, lưu localStorage.device_id |
g-username |
username user |
g-version |
version app, ví dụ 26.07.10.2 |
g-client |
client id app |
t |
btoa(btoa(btoa(unix_seconds))) — timestamp 3 lớp Base64 |
3. signing_key — nguyên liệu khóa
3.1. Lấy key ở đâu?
Trong Vuex store:
$store.state.signing_key
// DevTools:
document.querySelector('#app').__vue__.$store.state.signing_key
Lưu ý thực tế: giá trị store có thể khác
data.firebase_idtrả về từGET /users/me.
Luôn dùng đúng key mà browser đang ký (store / console), không chỉ dựa vào field API.
Key là 32 bytes, thường encode Base64 (có +, /, =), ví dụ:
cxbbf6td1EXcoEWlnk0eVmJwG1NJYhiqPxNcUXG+cBc=
Client cũng chấp nhận hex 64 ký tự.
3.2. Parse key (k_)
nếu chuỗi là hex hợp lệ và decode ra 32 bytes → dùng
else decode Base64 / Base64URL → 32 bytes → dùng
else lỗi: signing key must decode to 32 bytes
4. Dẫn xuất khóa AES (HKDF)
Trước khi AES-GCM, raw key 32 bytes được đưa qua HKDF-SHA256:
| Tham số | Giá trị |
|---|---|
| IKM | 32 bytes từ signing_key |
| Hash | SHA-256 |
| Salt | glk-gauth-v3-2026q3 |
| Info | aes-gcm-key |
| Output length | 32 bytes |
AES_KEY = HKDF-SHA256(
ikm = decode(signing_key),
salt = "glk-gauth-v3-2026q3",
info = "aes-gcm-key",
len = 32
)
Hằng số trong JS:
B_ = "glk-gauth"
E_ = "v3-2026" // sn(247)
S_ = "q3"
Sg = B_ + "-" + E_ + S_ // => "glk-gauth-v3-2026q3"
I_ = "aes-gcm-key"
AES_KEY import vào WebCrypto / OpenSSL dưới dạng AES-256-GCM.
5. Tạo payload trước khi mã hóa
5.1. Chuẩn hóa path (Pg + yu)
- Bỏ query (
?...) và hash (#...) - Ghép với base
https://gateway.golike.net/api - Chỉ lấy pathname
Ví dụ:
request URL:
/advertising/publishers/instagram/jobs?instagram_account_id=966624&data=null
signed path k:
/api/advertising/publishers/instagram/jobs
5.2. Hash body (j_)
body_str =
null/undefined → ""
string → chính nó
object → JSON.stringify(obj) // compact, không space
// JS: JSON.stringify → {"a":1}
q = SHA256_hex(body_str)
GET / HEAD / DELETE trong app: body ký = chuỗi rỗng ""
q = SHA256("")
= e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
5.3. Digest r (M_)
r = SHA256_hex( f"{t}:{device_id}:{q}:{salt}" )[0:16]
với salt = glk-gauth-v3-2026q3, t là timestamp milliseconds.
5.4. Object payload đầy đủ
Thứ tự key (quan trọng vì JSON.stringify giữ insertion order):
{
"t": 1783944428398,
"x": "z7Yv5E5ClYSc0gyyjllQ2w",
"d": "32484704-8a4e-4909-9d42-866773b321d6",
"u": 639111,
"n": "GET",
"k": "/api/advertising/publishers/instagram/jobs",
"q": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
"r": "286c4f5bd68ec1c4"
}
| Field | Mô tả |
|---|---|
t |
Date.now() (ms) |
x |
16 bytes random → Base64URL (no padding) |
d |
device UUID (g-device-id) |
u |
user id (number) |
n |
method upper-case |
k |
pathname đã chuẩn hóa |
q |
body hash |
r |
digest 16 hex chars |
Chuỗi plaintext:
plaintext = JSON.stringify(payload) // separators mặc định JS: không space
→ UTF-8 bytes
6. Mã hóa (encrypt) — H_
IV = 12 bytes random (crypto.getRandomValues)
CT = AES-256-GCM.Encrypt(
key = AES_KEY,
iv = IV,
pt = plaintext_utf8
)
// CT = ciphertext || 16-byte auth tag (WebCrypto / cryptography)
token_bytes = IV || CT
g-auth = Base64URL(token_bytes) // bỏ padding '='
Sơ đồ:
signing_key (b64/hex)
│
▼ decode 32B
IKM
│
▼ HKDF-SHA256(salt, info)
AES_KEY (32B)
│
│ ┌─ method, path, body, device, user, now ─┐
│ ▼ │
│ JSON payload {t,x,d,u,n,k,q,r} │
│ ▼ UTF-8 │
│ plaintext ──────────┐ │
│ │ │
▼ ▼ │
AES-256-GCM(IV=12B) ←── encrypt │
│ │
▼ │
IV || ciphertext+tag │
│ │
▼ Base64URL │
header g-auth ───────────────────────────────────┘
7. Giải mã (decrypt) — q_ / server / debug
raw = Base64URL_decode(g-auth)
IV = raw[0:12]
CT = raw[12:] // ciphertext + tag
plaintext = AES-256-GCM.Decrypt(AES_KEY, IV, CT)
payload = JSON.parse(plaintext)
Sau khi giải mã, server thường kiểm tra:
- Decrypt OK (key + IV + tag đúng)
- Fail →
decrypt_fail_check_signing_key_or_iv_or_tag_or_r_field
- Fail →
nkhớp HTTP methodkkhớp pathname canonical (vd./api/...)qkhớp SHA256 body thực tế nhận đượcd/ukhớp session / JWTtkhông lệch quá xa server time (ts_drift_ms)rkhớp lại công thức digest
Endpoint debug hữu ích:
POST /api/security/echo
Response có block gauth mô tả lỗi decode / match.
8. Ví dụ end-to-end (GET jobs)
Request
GET /api/advertising/publishers/instagram/jobs?instagram_account_id=966624&data=null
Authorization: Bearer <jwt>
g-device-id: 32484704-8a4e-4909-9d42-866773b321d6
g-username: vinhhacker
g-auth: Zmo3WFa5lp2X...
t: VFZSak5FMTZhekJPUkZGNVQwRTlQUT09
Payload đã giải mã (thực tế từ browser)
{
"t": 1783944428398,
"x": "z7Yv5E5ClYSc0gyyjllQ2w",
"d": "32484704-8a4e-4909-9d42-866773b321d6",
"u": 639111,
"n": "GET",
"k": "/api/advertising/publishers/instagram/jobs",
"q": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
"r": "286c4f5bd68ec1c4"
}
Tính lại q và r
q = SHA256("")
= e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
r = SHA256(
"1783944428398"
+ ":" + "32484704-8a4e-4909-9d42-866773b321d6"
+ ":" + q
+ ":" + "glk-gauth-v3-2026q3"
)[:16]
= 286c4f5bd68ec1c4
9. Header t (không nằm trong AES)
t = btoa(btoa(btoa(String(unix_seconds))))
Ví dụ:
unix = 1783944424
→ btoa × 3 → "VFZSak5FMTZhekJPUkZGNVQwRTlQUT09"
Đây là timestamp phụ (giây), tách biệt field t (ms) bên trong g-auth.
10. Pseudocode Python
import base64, hashlib, json, secrets, time
from cryptography.hazmat.primitives.ciphers.aead import AESGCM
from cryptography.hazmat.primitives.kdf.hkdf import HKDF
from cryptography.hazmat.primitives import hashes
SALT = "glk-gauth-v3-2026q3"
INFO = "aes-gcm-key"
def b64url(data: bytes) -> str:
return base64.urlsafe_b64encode(data).decode().rstrip("=")
def sha256_hex(s: str) -> str:
return hashlib.sha256(s.encode()).hexdigest()
def derive_key(signing_key_b64: str) -> bytes:
ikm = base64.b64decode(signing_key_b64)
return HKDF(
algorithm=hashes.SHA256(),
length=32,
salt=SALT.encode(),
info=INFO.encode(),
).derive(ikm)
def encrypt_g_auth(method, path, body, signing_key, device_id, user_id) -> str:
key = derive_key(signing_key)
iv = secrets.token_bytes(12)
t = int(time.time() * 1000)
q = sha256_hex(body if body is not None else "")
r = sha256_hex(f"{t}:{device_id}:{q}:{SALT}")[:16]
payload = {
"t": t,
"x": b64url(secrets.token_bytes(16)),
"d": device_id,
"u": user_id,
"n": method.upper(),
"k": path,
"q": q,
"r": r,
}
pt = json.dumps(payload, separators=(",", ":")).encode()
ct = AESGCM(key).encrypt(iv, pt, None) # ct + tag
return b64url(iv + ct)
def decrypt_g_auth(token: str, signing_key: str) -> dict:
key = derive_key(signing_key)
pad = "=" * (-len(token) % 4)
raw = base64.urlsafe_b64decode(token.replace("-", "+").replace("_", "/") + pad)
iv, ct = raw[:12], raw[12:]
pt = AESGCM(key).decrypt(iv, ct, None)
return json.loads(pt)
11. Lỗi thường gặp
| Triệu chứng | Nguyên nhân |
|---|---|
decrypt_fail_... |
Sai signing_key, hỏng token, hoặc không đúng thuật toán HKDF/AES |
AUTH_MISSING |
Không gửi g-auth (và/hoặc header bắt buộc khác) |
403 “cập nhật phiên bản…” |
Token thiếu/sai trên endpoint jobs; server từ chối client “cũ/không ký” |
| 200 ở browser, 403 ở script | Reuse g-auth cũ; hoặc path/body hash khác (space trong JSON, thiếu /api, …) |
| Decode local OK nhưng server fail | Key local ≠ key server đang expect; lấy lại từ store.state.signing_key |
12. Checklist implement đúng
signing_key= store browser, decode ra đúng 32 bytes- HKDF salt =
glk-gauth-v3-2026q3, info =aes-gcm-key - Path ký = pathname có prefix
/api/..., không query - GET body ký =
"" - POST body ký = cùng bytes body gửi đi (
JSONcompact nếu stringify) - Payload JSON không space, đúng thứ tự key
t,x,d,u,n,k,q,r - AES-GCM IV 12 bytes, output
Base64URL(IV || CT||TAG) - Mỗi request tạo
g-authmới
13. Tóm tắt một dòng
g-auth= Base64URL( IV₁₂ ‖ AES-256-GCMHKDF(signing_key)( JSON{method, path, bodyHash, device, user, time, nonce, digest} ) )
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file golike_gauth-0.1.2.tar.gz.
File metadata
- Download URL: golike_gauth-0.1.2.tar.gz
- Upload date:
- Size: 26.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.10
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
fbeed777d48db612e87100b9a50aa6307bd4b248545ec2fea7a55e45d3407091
|
|
| MD5 |
f03427b2844b684d6252bd401ca8d75c
|
|
| BLAKE2b-256 |
aa3a8784e9af81546f433fbff30055d94efe8e9c7a649d2f164d30f82f637fa7
|
File details
Details for the file golike_gauth-0.1.2-py3-none-any.whl.
File metadata
- Download URL: golike_gauth-0.1.2-py3-none-any.whl
- Upload date:
- Size: 17.9 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.10
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
9eb687eaee88d0885d1006bf67e2bdb0b1484da89ff4fce5dd117715a356564b
|
|
| MD5 |
8eae3f3f1a0c4302804ac31bf9432e63
|
|
| BLAKE2b-256 |
058c7e8a814a2dc2e3125c5f5a05aa76467efea5eabdf5f8769337610132028b
|