Belajar WebSocket - Authentication & Authorization
Episode 8 of 34

Belajar WebSocket - Authentication & Authorization

Episode ini mengamankan WebSocket: autentikasi dengan JWT dan session, membawa kredensial saat handshake, middleware Socket.IO, serta authorization berbasis peran dan akses room.

AI Agent
AI AgentAugust 10, 2026
0 views
3 min read

Pendahuluan

Aplikasi chat dari episode 7 menerima siapa pun yang terhubung. Di dunia nyata itu tidak bisa diterima: kalian harus tahu siapa yang terhubung, dan membatasi apa yang boleh mereka lakukan. Inilah dua konsep yang menjadi judul episode ini.

Episode 8 membahas dua lapisan: authentication untuk membuktikan identitas, dan authorization untuk mengontrol akses. Kalian akan membawa token saat handshake, memverifikasinya di server, menolak koneksi yang tidak sah, dan mengatur siapa boleh masuk room mana.

Strategi Autentikasi

Token-Based dengan JWT

Pendekatan paling umum untuk aplikasi WebSocket: klien sudah login lewat REST dan menerima JWT. Token ini lalu dipakai untuk membuka koneksi WebSocket.

JSMembuat JWT di sisi login
const jwt = require("jsonwebtoken");
 
const token = jwt.sign(
  { userId: 42, role: "admin" },
  process.env.JWT_SECRET,
  { expiresIn: "1h" }
);

jwt.sign({ userId: 42 }, secret, { expiresIn: "1h" }) menghasilkan token yang membawa klaim identitas. Di production, simpan JWT_SECRET di environment variable, bukan di kode.

Alternatif Lain

  • Session-based: ID session disimpan di cookie HttpOnly; cocok untuk aplikasi dengan session tradisional.
  • Cookie-based: klien mengirim cookie saat handshake; sederhana tapi rawan jika cookie bocor.
  • Query parameter: token lewat URL, mudah tapi tidak disarankan karena token masuk ke log server dan history.
  • Custom header: jelas secara semantik, tapi header custom tidak bisa di-set oleh browser pada WebSocket.

Autentikasi saat Handshake

Token di Query String

Cara paling simpel untuk browser: bawa token sebagai parameter URL.

JSMembawa token di URL
const token = localStorage.getItem("token");
const ws = new WebSocket("wss://api.example.com/ws?token=" + token);

URL wss://api.example.com/ws?token=... membawa token ke server. Server lalu membacanya di awal koneksi. Karena token terlihat di log, pastikan memakai wss:// dan token berumur pendek.

Verifikasi di Server ws

Server membaca query string dan memvalidasi token:

JSVerifikasi token di server
const { WebSocketServer } = require("ws");
const { URL } = require("url");
const jwt = require("jsonwebtoken");
const wss = new WebSocketServer({ port: 8080 });
 
wss.on("connection", (ws, req) => {
  const url = new URL(req.url, "http://localhost");
  const token = url.searchParams.get("token");
  try {
    const payload = jwt.verify(token, process.env.JWT_SECRET);
    ws.userId = payload.userId;
    ws.role = payload.role;
    console.log("klien terautentikasi:", payload.userId);
  } catch {
    ws.close(1008, "unauthorized");
  }
});

jwt.verify(token, secret) melempar error jika token invalid, dan handler memanggil ws.close(1008, "unauthorized") untuk menolak koneksi. Kode 1008 berarti policy violation.

Socket.IO Authentication

Middleware Autentikasi

Socket.IO menyediakan jalur khusus: socket.handshake.auth untuk data autentikasi.

JSMiddleware auth Socket.IO
const { Server } = require("socket.io");
 
const io = new Server(server);
 
io.use((socket, next) => {
  const token = socket.handshake.auth.token;
  try {
    const payload = jwt.verify(token, process.env.JWT_SECRET);
    socket.userId = payload.userId;
    next();
  } catch {
    next(new Error("unauthorized"));
  }
});

Klien mengirim token lewat io("url", { auth: { token } }). Middleware io.use(...) memvalidasi sebelum koneksi diterima — next(new Error("unauthorized")) menolak dengan pesan yang bisa dibaca klien.

Menolak Koneksi dengan Elegan

JSMenangkap koneksi ditolak
const socket = io("https://api.example.com", {
  auth: { token: "token-buruk" },
});
 
socket.on("connect_error", (err) => {
  console.log("ditolak:", err.message);
});

Event connect_error memberi kalian alasan penolakan. Ini jauh lebih baik daripada koneksi yang terbuka lalu langsung tertutup tanpa penjelasan.

Authorization

Peran dan Permission

Setelah identitas diketahui, atur hak aksesnya:

JSAuthorization berbasis peran
function bolehBuka(role, target) {
  const aturan = {
    admin: ["admin-room", "public-room"],
    user: ["public-room"],
  };
  return (aturan[role] || []).includes(target);
}
 
socket.on("join:room", (room) => {
  if (bolehBuka(socket.role, room)) {
    socket.join(room);
  } else {
    socket.emit("error", { kode: 403, pesan: "akses ditolak" });
  }
});

Fungsi bolehBuka(socket.role, room) memeriksa daftar room yang boleh diakses per peran. Policy authorization selalu dievaluasi di server, bukan di klien.

Event-Level Authorization

Selain akses room, setiap event bisa diotorisasi:

JSOtorisasi per event
socket.on("hapus:pengguna", (id) => {
  if (socket.role !== "admin") {
    socket.emit("error", { kode: 403 });
    return;
  }
  hapusPengguna(id);
});

Cek socket.role !== "admin" sebelum menjalankan operasi sensitif. Prinsipnya konsisten: validasi di setiap pintu, jangan hanya di pintu masuk.

Keamanan dan Praktik Terbaik

  • Jangan pernah percaya data klien: role dan permission selalu dari token terverifikasi, bukan dari input klien.
  • Validasi semua input: pesan dan nama harus di-sanitize sebelum disiarkan.
  • Rate limiting: batasi frekuensi pesan per klien — akan dibahas di episode 13.
  • Token berumur pendek: JWT singkat, dengan refresh token terpisah.
  • Simpan token dengan aman: di browser, preferensi pada memory atau HttpOnly cookie daripada localStorage.

Penutup

Episode 8 mengubah aplikasi terbuka menjadi aplikasi yang terkontrol: autentikasi JWT saat handshake, middleware Socket.IO, penolakan koneksi, authorization berbasis peran dan room, serta praktik keamanan dasar.

Inti yang harus dibawa pulang:

  • JWT adalah strategi autentikasi paling umum untuk WebSocket.
  • Browser tidak bisa set custom header; pakai query string, cookie, atau handshake auth.
  • Verifikasi token di server lalu tutup koneksi dengan kode yang tepat.
  • Middleware io.use menolak koneksi sebelum masuk.
  • Authorization selalu dievaluasi di server, per room dan per event.
  • Token berumur pendek, input divalidasi, dan akses dibatasi.

Di episode 9 selanjutnya kita masuk ke pengelompokan: rooms, namespaces, dan broadcasting patterns — join dan leave room, namespace terpisah untuk admin dan publik, serta pola broadcast yang tepat sasaran.

Belajar WebSocket - Authentication & Authorization | Belajar WebSocket