Autentikasi — API

Autentikasi memverifikasi siapa yang mengirim request. Token-based auth (paling umum untuk API): 1. Client login → POST /auth/login (email + password) 2. Server

Autentikasi memverifikasi siapa yang mengirim request.

Token-based auth (paling umum untuk API):

1. Client login → POST /auth/login (email + password)
2. Server verifikasi → return token
3. Client simpan token
4. Setiap request: Authorization: Bearer <token>
5. Server verifikasi token → beri akses

Login endpoint:

app.post("/auth/login", (req, res) => {
  const { email, password } = req.body;
  const user = db.prepare("SELECT * FROM users WHERE email = ?").get(email);

  if (!user || user.password !== hashPassword(password)) {
    return res.status(401).json({ error: "Email atau password salah" });
  }

  const token = generateToken(user.id);
  res.json({ token, user: { id: user.id, name: user.name } });
});

Auth middleware:

function requireAuth(req, res, next) {
  const token = req.headers.authorization?.replace("Bearer ", "");
  if (!token) return res.status(401).json({ error: "Token required" });

  const userId = verifyToken(token);
  if (!userId) return res.status(401).json({ error: "Invalid token" });

  req.userId = userId; // Tersedia di handler berikutnya
  next();
}

// Protected route
app.get("/profile", requireAuth, (req, res) => {
  const user = getUserById(req.userId);
  res.json(user);
});

401 vs 403:

JWT Deep Dive

Contoh di atas pakai "opaque token" generik. Paling umum di industri: JWT (JSON Web Token). JWT adalah string self-contained 3 bagian dipisah titik:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9     .    eyJzdWIiOiIxMjMiLCJuYW1lIjoiQnVkaSIsImV4cCI6MTcxNDYxMjM0NX0    .    SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
   Header (base64)                               Payload (base64 — decodable!)                                     Signature (verified by server)

Header — algoritma + tipe:

{"alg": "HS256", "typ": "JWT"}

Payload — klaim user:

{
  "sub": "123",          // subject (user id)
  "name": "Budi",
  "role": "admin",
  "iat": 1714611345,     // issued at
  "exp": 1714697745      // expires at (~24 jam)
}

SignatureHMAC-SHA256(base64(header) + "." + base64(payload), SECRET_KEY). Siapapun yang tidak punya SECRET_KEY tidak bisa buat JWT valid.

// Server membuat JWT
import jwt from "jsonwebtoken";

const token = jwt.sign(
  { sub: user.id, name: user.name, role: user.role },
  process.env.JWT_SECRET,
  { expiresIn: "24h" }
);

// Server verifikasi JWT
try {
  const decoded = jwt.verify(token, process.env.JWT_SECRET);
  // decoded.sub berisi user id
} catch (err) {
  // Invalid atau expired
}

⚠️ JWT pitfalls penting:

  1. Payload base64, bukan encrypted. Siapapun bisa decode dan lihat isinya. Jangan taruh data sensitif (password hash, internal ID, etc.).
  2. Tidak bisa di-revoke di server tanpa state tambahan. Kalau user logout, JWT lama masih valid sampai expire. Solusi: blacklist Redis, atau pakai refresh token pattern.
  3. alg: none attack. Beberapa library buggy menerima JWT tanpa signature. Selalu pakai library terupdate + verify algoritma.
  4. Secret management. SECRET_KEY minimal 256-bit random. Kalau bocor, attacker bisa buat JWT palsu.

Refresh Token Pattern

JWT umur pendek (15 menit). Refresh token umur panjang (7–30 hari), disimpan di httpOnly cookie.

Login:
  Server → { accessToken: JWT (15min), refreshToken: UUID (30d, httpOnly cookie) }

Client hit API:
  Header: Authorization: Bearer <accessToken>
  Kalau 401 → POST /auth/refresh (cookie ke-include otomatis)
  → Server verifikasi refresh token di DB → return new access token
  → Retry request asli

Trade-off: access token bocor (misal di log) dampaknya terbatas 15 menit, dan logout bisa di-enforce dengan menghapus refresh token di DB.

OAuth 2.0 — Untuk Third-Party Login

OAuth 2.0 memungkinkan user login dengan akun Google/GitHub/Facebook tanpa share password. Authorization Code Flow adalah yang paling umum:

1. User klik "Login with Google" di aplikasi kamu
2. Redirect ke Google: accounts.google.com/o/oauth2/v2/auth?
     client_id=YOUR_ID
     &redirect_uri=https://app.kamu/auth/callback
     &scope=openid email profile
     &state=RANDOM_CSRF_TOKEN

3. User login di Google + approve scope
4. Google redirect back: https://app.kamu/auth/callback?
     code=AUTHORIZATION_CODE
     &state=RANDOM_CSRF_TOKEN  ← kamu verify state untuk prevent CSRF

5. Server kamu exchange code for token:
   POST https://oauth2.googleapis.com/token
     { code, client_id, client_secret, redirect_uri, grant_type: "authorization_code" }

6. Response: { access_token, id_token, refresh_token }
7. Server decode id_token (JWT dari Google) → dapat user info
8. Buat session / JWT di aplikasi kamu

PKCE (Proof Key for Code Exchange) — wajib untuk SPA/mobile app:

API Keys — Server-to-Server

Untuk komunikasi backend-to-backend (tidak ada user browser):

Client: GET /api/data
Header: X-API-Key: sk_live_abc123xyz789

Best practice:

Matrix Pemilihan Auth Method

Use case Metode Alasan
Web app dengan cookie Session Simple, native browser support
SPA / Mobile JWT + refresh token Stateless, cocok cross-domain
Microservice internal mTLS atau JWT signed Infrastructure-level trust
Third-party integration OAuth 2.0 Standard, user consent jelas
Server-to-server (B2B) API Key Simple, tidak ada user context
Banking / finansial OAuth + FAPI Regulated, high-security

Yang akan kamu pelajari