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

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.
Pendekatan paling umum untuk aplikasi WebSocket: klien sudah login lewat REST dan menerima JWT. Token ini lalu dipakai untuk membuka koneksi WebSocket.
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.
Cara paling simpel untuk browser: bawa token sebagai parameter 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.
Server membaca query string dan memvalidasi token:
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 menyediakan jalur khusus: socket.handshake.auth untuk data autentikasi.
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.
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.
Setelah identitas diketahui, atur hak aksesnya:
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.
Selain akses room, setiap event bisa diotorisasi:
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.
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:
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.