Thoughts, tutorials, and insights about web development, design, and technology

## Introduction Dalam pengembangan aplikasi backend, satu tantangan umum adalah memastikan bahwa aplikasi berjalan sama di lingkungan pengembangan, staging, dan produksi. Perbedaan versi library, konfigurasi sistem, atau dependensi dapat menyebabkan bug yang sulit direproduksi. Docker menyediakan solusi dengan membungkus aplikasi dan semua dependensinya ke dalam suatu *container* yang terisolasi, sehingga menghasilkan lingkungan yang konsisten di mana pun container dijalankan. ## Pembahasan ### Apa Itu Docker? Docker adalah platform open-source yang memungkinkan developer membuat, mengirimkan, dan menjalankan aplikasi dalam kontainer. Kontainer adalah unit yang ringan dan portabel yang berisi kode aplikasi, runtime, library, dan setting yang diperlukan untuk menjalankan aplikasi tersebut. ### Konsep Dasar | Komponen | Penjelasan | |----------|------------| | **Image** | Template hanya-baca yang digunakan untuk membuat kontainer. Image berisi sistem operasi minimal, dependensi, dan kode aplikasi. | | **Container** | Instance yang dapat dijalankan dari sebuah image. Container berjalan terisolasi dari host tetapi berbagi kernel OS host. | | **Dockerfile** | Skrip teks yang berisi instrusi langkah demi langkah untuk membangun sebuah image. | | **Docker Hub** | Registry publik tempat kita dapat menyimpan dan mendistribusikan image Docker. | ### Mengapa Docker Berguna untuk Backend? - **Konsistensi Lingkungan**: Sama sekali tidak ada "works on my machine" lagi karena image yang sama digunakan di semua tahap. - **Skalabilitas**: Dengan container orchestration seperti Kubernetes atau Docker Swarm, kita dapat menyalin kontainer dengan mudah untuk menangani lalu lintas yang meningkat. - **Isolasi**: Setiap layanan (misalnya API, database, worker) dapat berjalan dalam kontainer terpisah, sehingga tidak saling mengganggu. - **Efisiensi Resource**: Kontainer lebih ringan daripada virtual machine karena tidak memerlukan OS tambahan per instance. ## Contoh (jika ada) Berikut contoh sederhana Dockerfile untuk aplikasi backend berbasis Node.js yang menampilkan pesan “Hello, World!” saat diakses melalui HTTP. ```dockerfile # 1. Gunakan image Node.js resmi sebagai base FROM node:18-alpine # 2. Set working directory di dalam container WORKDIR /app # 3. Salin file package.json dan package-lock.json (jika ada) COPY package*.json ./ # 4. Install dependensi RUN npm ci --only=production # 5. Salin seluruh kode aplikasi COPY . . # 6. Expose port yang akan digunakan oleh aplikasi (misal 3000) EXPOSE 3000 # 7. Perintah yang dijalankan ketika container mulai CMD ["node", "server.js"] ``` **file server.js** (letakkan di samma folder dengan Dockerfile) ```javascript const http = require('http'); const hostname = '0.0.0.0'; const port = 3000; const server = http.createServer((req, res) => { res.statusCode = 200; res.setHeader('Content-Type', 'text/plain'); res.end('Hello, World!\n'); }); server.listen(port, hostname, () => { console.log(`Server running at http://${hostname}:${port}/`); }); ``` **Langkah-langkah untukBuild dan Jalankan** 1. **Build image** ```bash docker build -t hello-node . ``` 2. **Jalankan container** ```bash docker run -p 3000:3000 --name hello-container hello-node ``` 3. Buka browser atau gunakan `curl`: ```bash curl http://localhost:3000 ``` Output yang diharapkan: `Hello, World!` ## Kesimpulan Docker adalah alat yang sangat berguna untuk mempermudah deployment dan pengelolaan aplikasi backend, terutama bagi pemula yang ingin memastikan aplikasi berjalan konsisten di berbagai lingkungan. Dengan memahami konsep image, container, dan Dockerfile, kita dapat mulai membungkus aplikasi kita ke dalam kontainer yang ringan, portabel, dan mudah diskalakan. Untuk langkah selanjutnya, pelajari Docker Compose untuk multi‑container aplikasi dan eksplorasi orchestration seperti Kubernetes untuk produksi skala besar.

## Introduction Dalam pengembangan aplikasi backend, satu tantangan umum adalah memastikan bahwa aplikasi berjalan sama di lingkungan pengembangan, staging, dan produksi. Perbedaan versi library, konfigurasi sistem, atau dependensi dapat menyebabkan bug yang sulit direproduksi. Docker menyediakan solusi dengan membungkus aplikasi dan semua dependensinya ke dalam suatu *container* yang terisolasi, sehingga menghasilkan lingkungan yang konsisten di mana pun container dijalankan. ## Pembahasan ### Apa Itu Docker? Docker adalah platform open-source yang memungkinkan developer membuat, mengirimkan, dan menjalankan aplikasi dalam kontainer. Kontainer adalah unit yang ringan dan portabel yang berisi kode aplikasi, runtime, library, dan setting yang diperlukan untuk menjalankan aplikasi tersebut. ### Konsep Dasar | Komponen | Penjelasan | |----------|------------| | **Image** | Template hanya-baca yang digunakan untuk membuat kontainer. Image berisi sistem operasi minimal, dependensi, dan kode aplikasi. | | **Container** | Instance yang dapat dijalankan dari sebuah image. Container berjalan terisolasi dari host tetapi berbagi kernel OS host. | | **Dockerfile** | Skrip teks yang berisi instrusi langkah demi langkah untuk membangun sebuah image. | | **Docker Hub** | Registry publik tempat kita dapat menyimpan dan mendistribusikan image Docker. | ### Mengapa Docker Berguna untuk Backend? - **Konsistensi Lingkungan**: Sama sekali tidak ada "works on my machine" lagi karena image yang sama digunakan di semua tahap. - **Skalabilitas**: Dengan container orchestration seperti Kubernetes atau Docker Swarm, kita dapat menyalin kontainer dengan mudah untuk menangani lalu lintas yang meningkat. - **Isolasi**: Setiap layanan (misalnya API, database, worker) dapat berjalan dalam kontainer terpisah, sehingga tidak saling mengganggu. - **Efisiensi Resource**: Kontainer lebih ringan daripada virtual machine karena tidak memerlukan OS tambahan per instance. ## Contoh (jika ada) Berikut contoh sederhana Dockerfile untuk aplikasi backend berbasis Node.js yang menampilkan pesan “Hello, World!” saat diakses melalui HTTP. ```dockerfile # 1. Gunakan image Node.js resmi sebagai base FROM node:18-alpine # 2. Set working directory di dalam container WORKDIR /app # 3. Salin file package.json dan package-lock.json (jika ada) COPY package*.json ./ # 4. Install dependensi RUN npm ci --only=production # 5. Salin seluruh kode aplikasi COPY . . # 6. Expose port yang akan digunakan oleh aplikasi (misal 3000) EXPOSE 3000 # 7. Perintah yang dijalankan ketika container mulai CMD ["node", "server.js"] ``` **file server.js** (letakkan di samma folder dengan Dockerfile) ```javascript const http = require('http'); const hostname = '0.0.0.0'; const port = 3000; const server = http.createServer((req, res) => { res.statusCode = 200; res.setHeader('Content-Type', 'text/plain'); res.end('Hello, World!\n'); }); server.listen(port, hostname, () => { console.log(`Server running at http://${hostname}:${port}/`); }); ``` **Langkah-langkah untukBuild dan Jalankan** 1. **Build image** ```bash docker build -t hello-node . ``` 2. **Jalankan container** ```bash docker run -p 3000:3000 --name hello-container hello-node ``` 3. Buka browser atau gunakan `curl`: ```bash curl http://localhost:3000 ``` Output yang diharapkan: `Hello, World!` ## Kesimpulan Docker adalah alat yang sangat berguna untuk mempermudah deployment dan pengelolaan aplikasi backend, terutama bagi pemula yang ingin memastikan aplikasi berjalan konsisten di berbagai lingkungan. Dengan memahami konsep image, container, dan Dockerfile, kita dapat mulai membungkus aplikasi kita ke dalam kontainer yang ringan, portabel, dan mudah diskalakan. Untuk langkah selanjutnya, pelajari Docker Compose untuk multi‑container aplikasi dan eksplorasi orchestration seperti Kubernetes untuk produksi skala besar.

## Introduction Dalam membangun aplikasi web modern, keamanan otentikasi adalah salah satu aspek yang tidak boleh diabaikan. Dua pendekatan populer untuk mengelola sesi pengguna adalah **JWT (JSON Web Token)** dan **Session-based authentication** (biasa menggunakan cookie dan server-side storage). Meskipun keduanya bertujuan untuk mengidentifikasi pengguna yang telah login, cara kerjanya, kelebihan, dan kekurangannya sangat berbeda. Artikel ini akan menjelaskan konsep dasar masing-masing, memberikan contoh sederhana dalam Node.js/Express, dan membantu Anda memutuskan kapan sebaiknya menggunakan JWT atau Session. ## Pembahasan ### Apa itu Session Authentication? - **Konsep**: Setelah login berhasil, server membuat sebuah *session identifier* (misal: `sessionId`) dan menyimpan data sessi (user ID, role, dll.) di penyimpanan server seperti memori, Redis, atau database. Identifier ini lalu dikirim ke klien sebagai cookie (`Set-Cookie: sessionId=abc123; HttpOnly; Secure`). - **Keamanan**: Cookie biasanya ditandai `HttpOnly` dan `Secure` sehingga tidak dapat diakses oleh JavaScript dan hanya dikirim melalui HTTPS. - **Kelebihan**: - Mudah untuk melakukan *logout* karena cukup menghapus data sessi di server. - Ukuran cookie kecil (hanya ID), sehingga tidak menambah beban jaringan signifikan. - **Kekurangan**: - Memerlukan penyimpanan server yang harus di-skala (misalnya menggunakan Redis cluster) ketika aplikasi menggunakan banyak instance. - Tidak cocok untuk arsitektur mikro‑layanan yang sepenuhnya stateless. ### Apa itu JWT? - **Konsep**: JWT adalah token yang dikodekan dalam format JSON dan ditandatangani secara kriptografis (HMAC atau RSA). Token berisi *claims* seperti `sub` (subject/user ID), `exp` (expiration), dan data kustom lain. Token ini dikirim ke klien (biasa dalam header `Authorization: Bearer <token>` atau cookie) dan divalidasi oleh server hanya melalui verifikasi tanda tangan, tanpa perlu menyimpan state di server. - **Keamanan**: Asalkan kunci rahasia (secret) atau kunci privat tidak bocor, token tidak dapat diubah tanpadeteksi. - **Kelebihan**: - Stateless: server tidak perlu menyimpan session, sehingga mudah di‑scale dan cocok untuk mikro‑layanan. - Token dapat berisi informasi yang dibutuhkan oleh layanan lain (misal: role, permissions) tanpa perlu panggilan tambahan ke server otentikasi. - **Kekurangan**: - Ukuran token lebih besar (biasa beberapa ratus byte) karena mengandung payload yang ditandatangani. - Pembatalan token sebelum masa berlaku (`exp`) membutuhkan mekanisme tambahan seperti *token blacklist* atau *revocation list*. - Tidak disarankan untuk menyimpan data sensitif dalam payload karena token hanya *base64url* di‑encode (bisa dengan mudah didekode). ### Kapan Memilih Mana? | Situasi | Direkomendasikan | |---------|------------------| | Aplikasi monolitik dengan sedikit instance, ingin logout instan, dan tidak mau mengelola ukuran token | **Session** | | Sistem mikro‑layanan, API gateway, atau layanan yang perlu skala horizontal tanpa menyimpan state | **JWT** | | Butuh token yang dapat dipakai oleh banyak layanan pihak ketiga (misal: login dengan OAuth2) | **JWT** | | Kebutuhan akan pencabutan akses segera (misal: perubahan password) tanpa menunggu token kadaluarsa | **Session** ( atau JWT + blacklist ) | ## Contoh (jika ada) Berikut contoh sederhana mengimplementasikan keduanya dengan **Node.js + Express**. Kita asumsikan sudah ada fungsi `verifyPassword(email, password)` yang mengembalikan `user` jika berhasil. ```javascript // ---- Dependency ---- const express = require('express'); const jwt = require('jsonwebtoken'); const session = require('express-session'); const RedisStore = require('connect-redis')(session); const redis = require('redis'); const app = express(); app.use(express.json()); // ---------- SESSION BASED ---------- const redisClient = redis.createClient({ url: 'redis://localhost:6379' }); redisClient.connect().catch(console.error); app.use( session({ store: new RedisStore({ client: redisClient }), secret: 's3cr3t-s3ss10n', resave: false, saveUninitialized: false, cookie: { httpOnly: true, secure: false, maxAge: 24 * 60 * 60 * 1000 }, // 1 hari }) ); app.post('/login/session', async (req, res) => { const { email, password } = req.body; const user = await verifyPassword(email, password); if (!user) return res.status(401).json({ msg: 'Invalid credentials' }); // Simpan user ID ke dalam session req.session.userId = user.id; return res.json({ msg: 'Login successful' }); }); app.get('/profile/session', (req, res) => { if (!req.session.userId) return res.status(401).json({ msg: 'Not authenticated' }); // Ambil data user dari DB atau cache res.json({ userId: req.session.userId, msg: 'Session based profile' }); }); // ---------- JWT BASED ---------- const JWT_SECRET = 'jwt-s3cr3t-key'; const JWT_EXPIRES_IN = '1h'; app.post('/login/jwt', async (req, res) => { const { email, password } = req.body; const user = await verifyPassword(email, password); if (!user) return res.status(401).json({ msg: 'Invalid credentials' }); const token = jwt.sign( { sub: user.id, role: user.role }, // payload JWT_SECRET, { expiresIn: JWT_EXPIRES_IN } ); return res.json({ token }); }); function authenticateJWT(req, res, next) { const auth = req.headers.authorization; if (!auth || !auth.startsWith('Bearer ')) return res.status(401).json({ msg: 'Missing or malformed token' }); const token = auth.slice(7); jwt.verify(token, JWT_SECRET, (err, payload) => { if (err) return res.status(401).json({ msg: 'Invalid or expired token' }); req.user = payload; // { sub, role, iat, exp } next(); }); } app.get('/profile/jwt', authenticateJWT, (req, res) => { // Tidak perlu menyimpan apa-apa di server, cukup gunakan req.user res.json({ userId: req.user.sub, role: req.user.role, msg: 'JWT based profile' }); }); app.listen(3000, () => console.log('Server running on http://localhost:3000')); ``` **Catatan:** - Untuk produksi, gunakan `secure: true` pada cookie, gunakan HTTPS, dan simpan rahasia (`secret`, `JWT_SECRET`) di variabel lingkungan. - Jika ingin membatalkan JWT sebelum masa berlaku, pertimbangkan menyimpan daftar token yang telah di‑revoke (misal: di Redis) dan memerikשיה בכל request. ## Kesimpulan Pemilihan antara JWT dan Session tergantung pada arsitektur aplikasi dan kebutuhan operasional Anda: - **Session** lebih cocok bila Anda ingin mengelola logout dengan mudah, memiliki sedikit instance server, dan tidak ingin menambah beban payload pada setiap request. - **JWT** unggul dalam sistem terdistribusi, mikro‑layanan, atau situasi di mana stateless dan skalabilitas adalah prioritas utama, asalkan Anda siap menangani masa berlaku token dan mekanisme pencabutan bila diperlukan. Kedua pendekatan aman bila diimplementasikan dengan benar—gunakan kunci kriptografi yang kuat, selalu sertakan flag `HttpOnly` dan `Secure` pada cookie, serta validasi token secara ketat. Dengan memahami trade‑off di atas, Anda dapat membuat keputusan yang tepat untuk menjaga keamanan dan kinerja aplikasi Anda.