JWT Bearer
JWT Bearer
OmniStream memakai JSON Web Token sebagai mekanisme autentikasi utama untuk REST API dan WebSocket. Setelah login, klien menerima token yang ditandatangani dengan HS256 dan dapat dikirim sebagai header Authorization: Bearer <token> di setiap request berikutnya.
Halaman ini menjelaskan struktur token, lifetime, dan cara memakainya dari klien non-browser (mis. skrip backend atau integrasi pihak ketiga). Untuk alur login dari browser yang memakai cookie httpOnly, lihat Cookie httpOnly.
Variabel lingkungan
Dari bagian JWT pada .env.example:
| Variabel | Default | Kegunaan |
|---|---|---|
JWT_SECRET | (wajib) | Kunci simetris HS256 minimal 32 karakter. Jangan pakai nilai default; generate dengan openssl rand -hex 32. |
JWT_EXPIRATION_HOURS | 24 | Umur token sejak iat. Token di luar rentang ini dianggap expired. |
Validasi JWT dilakukan di omni_common::JwtValidator (crates/omni-common/src/jwt.rs). Validator membungkus jsonwebtoken::decode dengan Validation::default() — yang artinya algoritma HS256, verifikasi exp, dan leeway nol. Nilai aud/iss tidak diperiksa karena OmniStream single-tenant.
Struktur payload
Token berisi AgentClaims yang didefinisikan di crates/omni-common/src/models/agent.rs:
Code
Contoh payload setelah decode:
Code
Klaim role di-serialize sebagai snake_case melalui enum AgentRole — hanya tiga nilai valid: admin, supervisor, agent. Pengkodean lain akan ditolak saat deserialisasi.
Lifetime dan rotasi
- Token berlaku
JWT_EXPIRATION_HOURSjam sejak diterbitkan (default 24 jam). - Tidak ada refresh token. Klien harus login ulang saat token kedaluwarsa.
- Saat ini tidak ada denylist/revocation: token yang sudah diterbitkan berlaku sampai
expmeski agent dinonaktifkan. Untuk mencabut akses sebelum waktunya, rotasiJWT_SECRET(akan menginvalidasi semua token aktif).
Memakai Bearer dari klien API
Semua endpoint di bawah /api/* kecuali /api/auth/login dan /api/health memerlukan token. Contoh dengan curl:
Code
Middleware JWT (crates/api-gateway/src/middleware/auth.rs) mencari token dengan urutan:
- Header
Authorization: Bearer <token> - Cookie
access_token(dipakai browser)
Jika keduanya tidak ada, middleware mengembalikan 401 Unauthorized. Jika token ada tetapi tidak valid (signature salah, kedaluwarsa, payload rusak), middleware juga mengembalikan 401.
Setelah validasi, AgentClaims dimasukkan ke Request::extensions() sehingga handler rute bisa membacanya lewat ekstractor Axum. Enforcement per-peran dilakukan oleh middleware RBAC terpisah — lihat RBAC.
WebSocket
ws-server (/ws?token=<JWT>) memakai validator yang sama. Perbedaan hanya pada transport: token dilewatkan sebagai query string karena WebSocket browser tidak dapat menambahkan header custom. Lihat WebSocket → Koneksi untuk detailnya.
Error umum
401 Unauthorizedtanpa body — headerAuthorizationtidak ada atau tidak dalam formatBearer <token>. Pastikan spasi tunggal antaraBearerdan token.401 Unauthorizeddengan body{ "error": "Invalid token" }— token kedaluwarsa atau signature tidak cocok. Login ulang dan pakai token baru.- Token berfungsi pada satu layanan tetapi tidak yang lain —
JWT_SECRETberbeda antar proses. Semua crate (api-gateway,ws-server, dll.) harus memakai nilai yang sama dari.env. JWT_SECRET must be at least 32 characterssaat start — isiJWT_SECRETdengan minimal 32 karakter. Jangan pakai defaultyour_jwt_secret_here_min_32_chars_longdi produksi.
Catatan keamanan
- Jangan menyimpan token mentah di localStorage pada browser. Frontend OmniStream memakai cookie
httpOnlyyang diset saat login (lihat Cookie httpOnly) supaya token tidak dapat dibaca JavaScript. - Gunakan HTTPS di produksi. Token Bearer yang melintasi HTTP dapat dicuri dengan sniffing.
- Rotasi secret secara berkala. Setiap rotasi menginvalidasi semua token aktif dan memaksa login ulang — rencanakan perubahan pada jendela maintenance.