OmniStream Docs
  • Panduan Pengguna
  • Developer
  • API Reference
Developer Hub
Pendahuluan
Autentikasi
    JWT BearerAlur login dan cookie httpOnlyRBAC dan matriks izin
Model Data
Webhook
WebSocket
Self-Hosting
Error & Rate Limit
Autentikasi

Alur login dan cookie httpOnly

Alur login dan cookie httpOnly

Browser tidak dapat menyimpan token JWT dengan aman di JavaScript. OmniStream memakai cookie httpOnly bernama access_token sebagai kanal sekunder yang mengangkut token sehingga frontend dapat melakukan request tanpa menyentuh token mentah.

Halaman ini merinci endpoint login, bentuk cookie yang dikembalikan, dan kapan memakai cookie vs header Authorization: Bearer.

Endpoint /api/auth/login

ItemNilai
MetodePOST
Path/api/auth/login
AuthTidak (public)
Content-Typeapplication/json

Request body:

Code
{ "email": "admin@omnistream.com", "password": "admin123" }

Response sukses (200 OK):

Body JSON:

Code
{ "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...", "agent": { "id": "6b6ccfc1-7e77-4b0c-8b45-5d4f52a3c8d1", "email": "admin@omnistream.com", "full_name": "Administrator", "role": "admin", "is_online": true, "max_concurrent_chats": 5, "last_seen_at": "2026-04-11T10:20:00Z" } }

Header Set-Cookie:

Code
access_token=eyJhbGciOi...; HttpOnly; Secure; SameSite=Strict; Path=/; Max-Age=86400

Nilai Max-Age adalah JWT_EXPIRATION_HOURS * 3600 — default 24 jam berarti 86400 detik.

Implementasi lengkap ada di crates/api-gateway/src/routes/auth.rs::login. Flow internalnya:

  1. Ambil baris agents berdasarkan email.
  2. Verifikasi password terhadap password_hash (Argon2id).
  3. Susun AgentClaims dengan exp = now + JWT_EXPIRATION_HOURS * 3600.
  4. Encode JWT HS256 memakai JWT_SECRET.
  5. Kirim token di dua tempat: JSON body dan header Set-Cookie.
  6. Rekam aktivitas login ke activity_logs secara asinkron.

Atribut cookie

Frontend SvelteKit hanya perlu cookie — JavaScript tidak perlu menyentuh nilainya. Atribut:

AtributNilaiAlasan
HttpOnlyyaMencegah XSS membaca token
SecureyaBrowser hanya mengirim cookie lewat HTTPS — di dev HTTP lokal, cookie tetap diset dan Chromium mengizinkannya lewat localhost
SameSite=StrictyaMencegah CSRF; cookie tidak dikirim pada cross-site navigation
Path=/yaCookie berlaku di semua rute backend
Max-Agesesuai JWT_EXPIRATION_HOURSBrowser otomatis menghapus setelah kedaluwarsa

Karena SameSite=Strict, frontend OmniStream harus dihosting pada origin yang sama atau subdomain yang sama dengan api-gateway supaya cookie ikut terkirim. Untuk deployment cross-origin, klien harus memakai header Authorization: Bearer dari body login.

Cara middleware membaca token

Middleware autentikasi di crates/api-gateway/src/middleware/auth.rs mencari token dengan urutan:

  1. Header Authorization: Bearer <token> (prioritas pertama)
  2. Cookie access_token

Jika keduanya ada, header Bearer menang. Jika keduanya tidak ada, middleware mengembalikan 401 Unauthorized.

Efeknya: klien API non-browser (skrip Python, curl, Postman) cukup menyimpan token dari body response dan mengirim sebagai header — cookie tidak diperlukan.

Endpoint terkait

GET /api/auth/me

Mengembalikan AgentPublic untuk token yang aktif. Dipakai frontend saat reload halaman untuk memulihkan state user dari cookie.

TerminalCode
curl -sS http://localhost:3000/api/auth/me \ -H "Authorization: Bearer $TOKEN"

GET /api/auth/token

Mengeluarkan JWT baru untuk agent yang sedang login. Frontend memakai endpoint ini setelah reload halaman untuk memperoleh token in-memory (yang diperlukan oleh WebSocket via query string ?token=), sementara cookie httpOnly tetap menjadi sumber kebenaran di browser.

TerminalCode
curl -sS http://localhost:3000/api/auth/token \ -H "Authorization: Bearer $OLD_TOKEN"

Response:

Code
{ "token": "eyJhbGciOiJIUzI1NiIs..." }

POST /api/auth/logout

Membersihkan cookie access_token dengan mengeluarkan cookie kosong ber-Max-Age=0 dan mencatat aktivitas logout. Token JWT itu sendiri tetap sah hingga exp-nya karena tidak ada denylist — frontend harus berhenti memakainya setelah logout.

TerminalCode
curl -sS -X POST http://localhost:3000/api/auth/logout \ -H "Authorization: Bearer $TOKEN"

Kapan memakai cookie vs Bearer

KlienRekomendasi
SvelteKit frontend OmniStreamCookie (otomatis di-set oleh /api/auth/login)
Browser pihak ketiga pada origin yang samaCookie
Skrip server-to-server, worker, CLIHeader Authorization: Bearer
Webhook receiver (pihak ketiga memanggil kita)Tidak relevan — webhook memakai HMAC signature, bukan JWT
WebSocket (browser)Query string ?token= karena browser WebSocket tidak bisa menambah header

Troubleshooting

  • Frontend login 200, tetapi request berikutnya 401 — kemungkinan origin berbeda. Periksa cookie di DevTools → Application → Cookies. Jika tidak ada cookie, perhatikan SameSite=Strict dan pastikan frontend berada di origin yang sama dengan api-gateway.
  • Set-Cookie muncul di response tetapi browser tidak menyimpannya — bisa karena atribut Secure pada koneksi non-HTTPS (beberapa browser menolak di luar localhost). Pakai HTTPS di produksi.
  • Request dari Postman gagal 401 — Postman tidak otomatis meneruskan cookie antar request. Pakai header Authorization: Bearer yang diambil dari body /api/auth/login.
  • Token dari cookie dan header berbeda — pastikan Anda memakai token yang sama. Middleware memproses header lebih dulu sehingga Bearer "menang".

Catatan keamanan

  • Jangan menaruh token di URL path/query kecuali untuk WebSocket — URL sering dicatat oleh server log dan histori browser.
  • Rotasi JWT_SECRET menginvalidasi semua token aktif termasuk cookie yang sudah diset; browser masih mengirim cookie lama sampai Max-Age habis, tetapi middleware akan menolaknya dengan 401, memaksa login ulang.
  • Serangan CSRF dicegah oleh SameSite=Strict. Jangan pernah mengubahnya ke Lax/None tanpa menambahkan token CSRF header terpisah.
Last modified on June 8, 2026
JWT BearerRBAC dan matriks izin
On this page
  • Endpoint /api/auth/login
  • Atribut cookie
  • Cara middleware membaca token
  • Endpoint terkait
    • GET /api/auth/me
    • GET /api/auth/token
    • POST /api/auth/logout
  • Kapan memakai cookie vs Bearer
  • Troubleshooting
  • Catatan keamanan
JSON
JSON
JSON