Endpoint API Addon — Publik & Header Kustom
Membuat satu endpoint API addon bisa dipanggil tanpa token AlurKerja, dan meneruskan header pemanggil (mis. x-token) ke script/REST addon
Selain actions (dipanggil dari Service Task BPMN — lihat Pembuatan Addon pada AlurKerja), satu addon juga bisa mendeklarasikan blok apis di index.json: endpoint API milik addon itu sendiri, dipanggil langsung oleh pihak eksternal (bukan lewat BPMN). Secara default endpoint ini tetap butuh token AlurKerja seperti endpoint lain — halaman ini soal dua pengecualian opt-in per endpoint:
public— satu endpointapisbisa dipanggil tanpa token AlurKerja sama sekali.allowed-headers— header yang dikirim pemanggil (mis.x-token) diteruskan ke eksekusi addon, supaya addon publik bisa mengamankan dirinya sendiri.
Halaman ini melanjutkan Pembuatan Addon pada AlurKerja: struktur addon dan kontrak run(ctx) di sana tetap berlaku. Kalau addon-nya juga memakai ctx.svc untuk memanggil balik AlurKerja, itu topik terpisah — lihat AlurKerja Python SDK untuk Script Addon; ctx.svc hanya ada di jalur Service Task BPMN, tidak pernah di jalur apis yang dibahas di sini.
1. Cara Kerja
Pemanggil eksternal (tanpa token AlurKerja)
│ header: x-token: <secret>
▼
{ANY} /api/v1/integration/addons/{addon}/{tenant_setting_id}/api/{action}
│
▼
integration-service
1. Tidak ada Authorization header sama sekali?
→ diteruskan TANPA identitas, HANYA untuk bentuk path ini
2. Baca baris addon + endpoint `action` dari database
3. index.json apis.<action>.public == true ?
YA → lanjut, tanpa syarat token
TIDAK → 401 Authorization header required
4. Salin header yang terdaftar di apis.<action>.allowed-headers
│
▼
python3 scripts/<endpoint>/<endpoint>.py --run <ctx.json>
ctx["headers"] = { "x-token": "<secret>" }
│
▼
Script memvalidasi x-token sendiri, lalu jalankan logikanyaHal yang perlu diingat:
- Per endpoint, bukan per addon. Endpoint lain di addon yang sama yang tidak menuliskan
publictetap butuh token seperti biasa — defaultnyapublic: falsekalau key-nya tidak ada diindex.json. Menambahkanpublicdi satu endpoint tidak membuka endpoint lain. - Pemanggil yang tetap mengirim token AlurKerja tidak dirugikan maupun diistimewakan. Token yang valid tetap divalidasi dan tetap membawa
parameters.user_tokenseperti biasa (lihat Bagian 3); token yang salah tetap ditolak401—public: truetidak pernah menurunkan token yang salah jadi permintaan anonim yang diloloskan. - Platform tidak lagi memeriksa siapa pemanggilnya untuk endpoint yang
public. Kalau addon perlu membatasi siapa yang boleh memanggil, addon sendiri yang mengamankannya — pola yang dipakai adalah shared secret di header kustom (lihat Bagian 2 dan 4). - Berlaku hanya untuk endpoint di blok
apis, dipanggil lewat.../api/{action}.actions(Service Task BPMN) tidak terpengaruh sama sekali olehpublic/allowed-headers.
2. Opt-in di index.json
Tambahkan public dan/atau allowed-headers di definisi satu endpoint, di dalam blok apis:
{
"apis": {
"get_record_by_email": {
"name": "Get Record By Email API",
"description": "Ambil record berdasarkan email, dipanggil sistem eksternal.",
"type": "SCRIPT",
"endpoint": "get_record_by_email",
"public": true,
"allowed-headers": ["x-token"]
}
}
}| Key | Wajib? | Arti |
|---|---|---|
public | Tidak, default false | true = endpoint ini bisa dipanggil tanpa Authorization header sama sekali |
allowed-headers | Tidak, default kosong | Daftar nama header yang diteruskan ke eksekusi addon. Cocok tanpa memandang huruf besar/kecil |
Mendaftarkan "Authorization" di allowed-headers tidak berefek apa pun — nilai itu tetap hanya lewat parameters.user_token, tidak pernah digandakan ke ctx["headers"]["Authorization"]. Satu token, satu jalur, satu nama.
Nilai public/allowed-headers disimpan saat addon di-install atau di-publish — addon yang sudah terpasang sebelum field ini ditambahkan harus dipublish ulang.
3. Isi ctx yang Diterima Script
{
"variables": {},
"parameters": {
"user_token": ""
},
"configuration": {},
"runkey": "api-exec-1789123456789-get_record_by_email",
"headers": {
"x-token": "secret-dari-pemanggil"
}
}| Field | Keterangan |
|---|---|
parameters.user_token | Token AlurKerja milik pemanggil TANPA prefix Bearer . Kosong ("") kalau pemanggil tidak mengirim Authorization — normal untuk endpoint public. |
headers | HANYA berisi header yang terdaftar di allowed-headers DAN benar-benar dikirim pemanggil. Header yang tidak terdaftar tidak pernah muncul di sini, dan header yang terdaftar tapi tidak dikirim TIDAK muncul sebagai key kosong — script harus cek keberadaan key-nya, bukan menganggap selalu ada. |
headers hanya ada di jalur apis (.../api/{action}). Jalur Service Task BPMN (actions, .../execute/{action}) tidak mengenal allowed-headers — tidak ada request HTTP masuk untuk diambil headernya di jalur itu.
4. Contoh: Endpoint Publik dengan Shared Secret
4.1 Script
def run(ctx):
headers = ctx.get("headers") or {}
token = headers.get("x-token", "")
# Simpan secret ini di config addon (bukan di kode) saat setup, mis. lewat
# tenant_settings addon. Dibandingkan dengan konstanta waktu-tetap kalau
# butuh lebih ketat dari perbandingan string biasa.
expected = (ctx.get("configuration") or {}).get("shared_secret", "")
if not token or token != expected:
return {"status": 401, "data": {"message": "Token tidak valid"}}
email = (ctx.get("parameters") or {}).get("email", "")
if not email:
return {
"status": 400,
"data": {"message": "Parameter 'email' wajib diisi"},
}
# ... ambil record dari master data, dsb.
record = {"email": email, "status": "found"}
return {"status": "ok", "data": record}Field top-level status di sini adalah kanal khusus jalur API — "ok"/integer 100–599 dipetakan langsung jadi HTTP status response. Lihat penjelasan lengkapnya di dokumen backend ADDON_ACTION_EXECUTION_API.md (bagian "API Type Action") kalau perlu detail pemetaannya.
4.2 Panggilan dari Luar
Tanpa token AlurKerja sama sekali — cukup shared secret di header:
curl -X GET \
"https://<host>/api/v1/integration/addons/telegram-account/42/api/get_record_by_email?email=user@example.com" \
-H "x-token: secret-dari-pemanggil"5. Endpoint Tipe REST
Untuk apis.<key>.type bernilai "REST" (bukan "SCRIPT"), allowed-headers diteruskan sebagai header HTTP ke request upstream addon — menimpa nilai statis yang sama dari konfigurasi addon kalau ada, karena allowed-headers mewakili apa yang pemanggil kirim untuk request itu, bukan nilai tetap.
{
"apis": {
"hello": {
"type": "REST",
"method": "GET",
"endpoint": "/echo",
"public": true,
"allowed-headers": ["x-token"]
}
}
}6. Aturan Keamanan
| Lakukan | Hindari |
|---|---|
Simpan shared secret di konfigurasi addon (configuration/tenant_settings), bukan hardcode di script | Membandingkan header ke string yang ditulis langsung di kode sumber |
Set public: true cuma di endpoint yang memang perlu dipanggil tanpa token AlurKerja | Mengaktifkan public di seluruh apis "supaya gampang" |
Validasi headers di awal run(ctx), tolak sebelum baca parameters/configuration lain | Mempercayai ctx["headers"] tanpa validasi apa pun karena "kan sudah lewat allowed-headers" — allowed-headers cuma mengatur PENERUSAN, bukan VALIDASI |
Daftarkan cuma header yang benar-benar dipakai script di allowed-headers | Mendaftarkan header secara longgar (mis. seluruh header custom) tanpa alasan |
7. Troubleshooting
| Gejala | Penyebab | Solusi |
|---|---|---|
Selalu 401 Authorization header required walau sudah set public: true | Addon belum dipublish ulang setelah menambahkan public | Publish ulang addon |
ctx["headers"] selalu kosong walau header sudah dikirim | Nama header tidak terdaftar di allowed-headers, atau salah eja | Cocokkan persis nama header yang didaftarkan (tidak case-sensitive, tapi harus sama karakternya) |
ctx["headers"]["Authorization"] selalu tidak ada walau Authorization didaftarkan di allowed-headers | Memang disengaja — Authorization tidak pernah digandakan ke headers | Baca token pemanggil dari parameters.user_token, bukan headers |
| Endpoint lain di addon yang sama jadi ikut publik | Tidak mungkin dari fitur ini — public per endpoint. Periksa apakah endpoint lain juga menuliskan public: true sendiri | Hapus public dari endpoint yang seharusnya tetap butuh token |
