Teknologi

Penjelasan Otentikasi API (Akhirnya) — Otentikasi Dasar, Bearer & JWT

D
Donar Azhar
21 Feb 2026 233 views
Penjelasan Otentikasi API (Akhirnya) — Otentikasi Dasar, Bearer & JWT

1. Apa Itu Otentikasi API?

Bayangkan kamu memiliki apartemen. Di depan pintu ada satpam. Setiap tamu yang datang harus membuktikan identitasnya sebelum diizinkan masuk. Satpam bisa meminta:

  • Kartu tanda pengenal (username & password)
  • Stiker khusus yang diberikan manajemen gedung (token)
  • Gelang pintar yang bisa diverifikasi otomatis (JWT)

Otentikasi API bekerja persis seperti itu — ini adalah mekanisme yang memastikan bahwa hanya pihak yang berwenang yang bisa mengakses sumber daya di sebuah API.

Secara teknis, otentikasi API adalah proses di mana klien (aplikasi yang memanggil API) membuktikan identitasnya kepada server (API yang dipanggil) sebelum server memproses permintaan tersebut.

Otentikasi vs Otorisasi — Jangan Tertukar!

Dua istilah ini sering membingungkan. Berikut perbedaan sederhananya:

Konsep Pertanyaan yang Dijawab Contoh
Otentikasi Siapa kamu? "Kamu adalah pengguna dengan ID 42"
Otorisasi Apa yang boleh kamu lakukan? "Pengguna 42 boleh membaca data, tapi tidak boleh menghapus"

Otentikasi selalu datang lebih dulu. Kamu tidak bisa mengotorisasi seseorang yang belum dikenali identitasnya.

2. Mengapa Otentikasi Itu Penting?

Tanpa otentikasi, API kamu ibarat toko yang semua pintu dan lacinya terbuka — siapa pun bisa masuk, mengambil data, memodifikasi catatan, atau bahkan menghapus semua data.

Konsekuensi nyata jika API tidak memiliki otentikasi yang baik:

  • Kebocoran data pengguna — data pribadi, nomor kartu kredit, alamat email tersebar bebas
  • Penyalahgunaan sumber daya — bot bisa membebani server tanpa batas (DDoS)
  • Manipulasi data — pihak tidak bertanggung jawab bisa mengubah atau menghapus data penting
  • Kerugian finansial — API layanan berbayar bisa disalahgunakan tanpa batas

Itulah mengapa memahami dan mengimplementasikan otentikasi yang tepat adalah fondasi utama keamanan aplikasi modern.

3. Basic Authentication (Otentikasi Dasar)

Apa Itu?

Basic Authentication adalah metode otentikasi paling sederhana dan paling tua di dunia HTTP. Caranya: klien mengirimkan username dan password setiap kali membuat permintaan ke API.

Analoginya seperti setiap kali masuk kantor, kamu harus menyebutkan nama lengkap dan nomor KTP kamu kepada satpam — berulang-ulang di setiap kunjungan.

Cara Kerjanya

Berikut alur Basic Authentication:

1. Klien ingin mengakses resource API
2. Server merespons dengan 401 Unauthorized
3. Klien mengirim header: Authorization: Basic <kredensial>
4. Server memverifikasi kredensial
5. Jika valid → akses diberikan (200 OK)
   Jika tidak valid → akses ditolak (401 Unauthorized)

Bagaimana kredensial dibentuk?

Username dan password digabung dengan titik dua, lalu di-encode menggunakan Base64:

username:password  →  dXNlcm5hbWU6cGFzc3dvcmQ=

Kemudian dikirim dalam HTTP header:

GET /api/data HTTP/1.1
Host: api.contoh.com
Authorization: Basic dXNlcm5hbWU6cGFzc3dvcmQ=

Contoh Kode

Menggunakan cURL:

curl -u username:password https://api.contoh.com/data

# Atau secara manual dengan header:
curl -H "Authorization: Basic dXNlcm5hbWU6cGFzc3dvcmQ=" https://api.contoh.com/data

Menggunakan JavaScript (Fetch API):

const username = 'admin';
const password = 'rahasia123';
const credentials = btoa(`${username}:${password}`);

const response = await fetch('https://api.contoh.com/data', {
  headers: {
    'Authorization': `Basic ${credentials}`
  }
});

const data = await response.json();

Menggunakan Python (requests):

import requests

response = requests.get(
    'https://api.contoh.com/data',
    auth=('admin', 'rahasia123')  # Library otomatis encode ke Base64
)

print(response.json())

⚠️ Penting: Base64 BUKAN Enkripsi!

Banyak orang salah paham bahwa Base64 memberikan keamanan. Tidak! Base64 hanyalah format encoding — siapa pun bisa mendekode-nya dalam hitungan detik:

dXNlcm5hbWU6cGFzc3dvcmQ=  →  username:password

Ini artinya Basic Auth HARUS selalu digunakan bersama HTTPS agar kredensial tidak bisa dicegat di tengah jalan.

Kelebihan & Kekurangan

✅ Kelebihan ❌ Kekurangan
Sangat sederhana diimplementasikan Password dikirim di setiap request
Didukung hampir semua klien HTTP Tidak ada mekanisme "logout" yang nyata
Cocok untuk testing dan internal tools Harus selalu pakai HTTPS (tidak opsional)
Tidak perlu state di server Rentan jika terjadi kebocoran (semua request terekspos)

4. Bearer Token

Apa Itu?

Bearer Token adalah string unik yang diberikan server kepada klien setelah login berhasil. Setelah mendapat token ini, klien menggunakannya untuk mengakses resource — tanpa perlu mengirim username/password lagi.

Analoginya seperti tiket konser. Kamu membeli tiket di loket (login), lalu menunjukkan tiket itu di pintu masuk (setiap request). Siapa pun yang memegang tiket itu bisa masuk — itulah mengapa disebut "Bearer" (pemegang).

Cara Kerjanya

1. Klien mengirim username & password ke endpoint login
2. Server memverifikasi → menghasilkan token unik → menyimpannya di database
3. Server mengirim token kepada klien
4. Klien menyimpan token (di memori, localStorage, atau cookie)
5. Setiap request berikutnya, klien menyertakan token di header
6. Server mencari token di database → jika ada dan valid → izinkan akses

Token dikirim dalam HTTP header seperti ini:

GET /api/profil HTTP/1.1
Host: api.contoh.com
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...

Contoh Kode

Langkah 1 — Login dan dapatkan token:

// Login untuk mendapatkan token
const loginResponse = await fetch('https://api.contoh.com/auth/login', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    username: 'admin',
    password: 'rahasia123'
  })
});

const { token } = await loginResponse.json();
// token = "abc123xyz789..."

Langkah 2 — Gunakan token untuk request berikutnya:

const response = await fetch('https://api.contoh.com/profil', {
  headers: {
    'Authorization': `Bearer ${token}`
  }
});

const profil = await response.json();

Implementasi server sederhana (Node.js/Express):

// Middleware validasi Bearer Token
function autentikasiToken(req, res, next) {
  const authHeader = req.headers['authorization'];
  const token = authHeader && authHeader.split(' ')[1];

  if (!token) {
    return res.status(401).json({ error: 'Token tidak ditemukan' });
  }

  const pengguna = database.cariTokenValid(token);

  if (!pengguna) {
    return res.status(403).json({ error: 'Token tidak valid' });
  }

  req.pengguna = pengguna;
  next();
}

app.get('/api/profil', autentikasiToken, (req, res) => {
  res.json({ data: req.pengguna });
});

Masalah dengan Bearer Token Sederhana

Token sederhana yang disimpan di database punya satu kelemahan besar: server harus melakukan query ke database setiap kali ada request. Bayangkan API dengan jutaan pengguna aktif — ini menjadi bottleneck yang sangat berat.

Di sinilah JWT hadir sebagai solusi.

Kelebihan & Kekurangan

✅ Kelebihan ❌ Kekurangan
Lebih aman dari Basic Auth Server harus query DB setiap request (jika stateful)
Password tidak dikirim berulang kali Butuh penyimpanan token yang aman di klien
Mendukung "logout" dengan menghapus token Token bisa dicuri (man-in-the-middle)
Mudah dibatasi (revoke token kapan saja) Perlu manajemen siklus hidup token

5. JWT (JSON Web Token)

Apa Itu?

JWT (JSON Web Token) adalah standar terbuka (RFC 7519) untuk membuat token yang bisa membawa informasi sekaligus memverifikasi dirinya sendiri — tanpa perlu database sama sekali.

Analoginya seperti paspor. Paspor berisi identitasmu, diterbitkan oleh otoritas berwenang (pemerintah), dan bisa diverifikasi kapan saja hanya dengan memeriksa stempel dan tanda tangan di dalamnya — tanpa perlu menelepon kantor imigrasi setiap saat.

Struktur JWT

JWT terdiri dari tiga bagian yang dipisahkan tanda titik (.):

xxxxx.yyyyy.zzzzz
  │      │      │
Header Payload Signature

Contoh JWT nyata:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.
eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.
SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c

Bagian 1: Header

Header berisi dua informasi: jenis token dan algoritma enkripsi yang digunakan.

{
  "alg": "HS256",   // Algoritma: HMAC SHA-256
  "typ": "JWT"      // Tipe token
}

Kemudian di-encode Base64URL:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9

Bagian 2: Payload (Claims)

Payload berisi klaim — informasi tentang pengguna dan metadata token. Ada tiga jenis klaim:

Registered Claims (Standar):

{
  "iss": "https://auth.contoh.com",   // Issuer — siapa yang menerbitkan token
  "sub": "user_42",                   // Subject — siapa pemilik token
  "aud": "https://api.contoh.com",    // Audience — untuk siapa token ini
  "exp": 1700000000,                  // Expiration — kapan token kedaluwarsa
  "iat": 1699996400,                  // Issued At — kapan token dibuat
  "nbf": 1699996400                   // Not Before — token belum valid sebelum waktu ini
}

Custom Claims (Sesuka kita):

{
  "sub": "user_42",
  "exp": 1700000000,
  "nama": "Budi Santoso",
  "role": "admin",
  "email": "[email protected]",
  "izin": ["baca", "tulis", "hapus"]
}

⚠️ Ingat: Payload tidak dienkripsi, hanya di-encode. Jangan menyimpan informasi sensitif (password, data kartu kredit) di sini!

Bagian 3: Signature (Tanda Tangan)

Inilah bagian terpenting JWT. Tanda tangan dibuat dengan cara:

HMACSHA256(
  base64UrlEncode(header) + "." + base64UrlEncode(payload),
  secret_key
)

Contoh dalam pseudocode:

data = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ1c2VyXzQyIn0"
kunci_rahasia = "kunci-super-rahasia-server-kita"

tanda_tangan = HMAC_SHA256(data, kunci_rahasia)

Tanda tangan ini membuktikan bahwa token belum dimodifikasi. Jika seseorang mengubah payload (misalnya mengubah role dari "user" menjadi "admin"), tanda tangan tidak akan cocok lagi, dan server akan menolaknya.

Cara Kerja JWT End-to-End

┌─────────┐                               ┌─────────┐
│  Klien  │                               │ Server  │
└────┬────┘                               └────┬────┘
     │                                         │
     │  POST /login {username, password}        │
     │ ────────────────────────────────────────►│
     │                                         │
     │          Verifikasi kredensial           │
     │          Buat JWT dengan payload         │
     │          Tandatangani dengan kunci rahasia│
     │                                         │
     │  200 OK { token: "eyJ..." }             │
     │ ◄────────────────────────────────────────│
     │                                         │
     │  GET /api/data                          │
     │  Authorization: Bearer eyJ...           │
     │ ────────────────────────────────────────►│
     │                                         │
     │          Decode header & payload         │
     │          Hitung ulang signature          │
     │          Cocokkan dengan signature token │
     │          Cek exp, iss, aud               │
     │          Tidak perlu query database! ✓   │
     │                                         │
     │  200 OK { data: ... }                   │
     │ ◄────────────────────────────────────────│

Contoh Kode Lengkap

Membuat dan memverifikasi JWT (Node.js dengan jsonwebtoken):

const jwt = require('jsonwebtoken');

const KUNCI_RAHASIA = process.env.JWT_SECRET;

// ===== MEMBUAT TOKEN (saat login) =====
function buatToken(dataPengguna) {
  const payload = {
    sub: dataPengguna.id,
    nama: dataPengguna.nama,
    email: dataPengguna.email,
    role: dataPengguna.role
  };

  const token = jwt.sign(payload, KUNCI_RAHASIA, {
    expiresIn: '1h',
    issuer: 'api.contoh.com',
    audience: 'app.contoh.com'
  });

  return token;
}

// ===== MEMVERIFIKASI TOKEN (middleware) =====
function verifikasiJWT(req, res, next) {
  const authHeader = req.headers['authorization'];
  const token = authHeader && authHeader.split(' ')[1];

  if (!token) {
    return res.status(401).json({ error: 'Token tidak ditemukan' });
  }

  try {
    const decoded = jwt.verify(token, KUNCI_RAHASIA, {
      issuer: 'api.contoh.com',
      audience: 'app.contoh.com'
    });

    req.pengguna = decoded;
    next();
  } catch (error) {
    if (error.name === 'TokenExpiredError') {
      return res.status(401).json({ error: 'Token kedaluwarsa, silakan login ulang' });
    }
    return res.status(403).json({ error: 'Token tidak valid' });
  }
}

// ===== ENDPOINT LOGIN =====
app.post('/login', async (req, res) => {
  const { username, password } = req.body;

  const pengguna = await db.cariPengguna(username);
  if (!pengguna || !bcrypt.compareSync(password, pengguna.passwordHash)) {
    return res.status(401).json({ error: 'Kredensial salah' });
  }

  const token = buatToken(pengguna);
  res.json({ token });
});

// ===== ENDPOINT YANG DILINDUNGI =====
app.get('/api/profil', verifikasiJWT, (req, res) => {
  res.json({ pengguna: req.pengguna });
});

Menggunakan JWT di klien (JavaScript):

// Simpan token dengan aman
localStorage.setItem('jwt_token', token);

// Fungsi helper untuk request berautentikasi
async function apiFetch(url, options = {}) {
  const token = localStorage.getItem('jwt_token');

  return fetch(url, {
    ...options,
    headers: {
      ...options.headers,
      'Authorization': `Bearer ${token}`,
      'Content-Type': 'application/json'
    }
  });
}

// Penggunaan
const response = await apiFetch('/api/profil');
const profil = await response.json();

Konsep Penting: Access Token & Refresh Token

JWT biasanya memiliki masa kedaluwarsa yang singkat (15 menit – 1 jam) demi keamanan. Tapi tentu tidak nyaman jika pengguna harus login setiap jam. Solusinya adalah pasangan Access Token dan Refresh Token:

Access Token:
  - Masa berlaku singkat (15–60 menit)
  - Dikirim di setiap request API
  - Jika dicuri, kerugian terbatas (hanya berlaku sebentar)

Refresh Token:
  - Masa berlaku panjang (7–30 hari)
  - Disimpan lebih aman (httpOnly cookie)
  - HANYA digunakan untuk mendapatkan Access Token baru
  - Jika dicuri, bisa direvoke di server

Alur Refresh Token:

1. Access Token kedaluwarsa → API mengembalikan 401
2. Klien mengirim Refresh Token ke /auth/refresh
3. Server memverifikasi Refresh Token
4. Server mengeluarkan Access Token baru
5. Klien melanjutkan request dengan token baru

Kelebihan & Kekurangan JWT

✅ Kelebihan ❌ Kekurangan
Stateless — tidak perlu query database Sulit di-revoke sebelum kedaluwarsa
Skalabel untuk sistem terdistribusi Ukuran token lebih besar dari token sederhana
Membawa data (tidak perlu lookup tambahan) Payload bisa didekode (jangan simpan data sensitif)
Bisa digunakan lintas domain (Cross-Origin) Implementasi yang salah bisa berbahaya
Standar terbuka, banyak library tersedia Butuh pemahaman lebih untuk menggunakan dengan benar

6. Perbandingan Ketiga Metode

Tabel Perbandingan Lengkap

Aspek Basic Auth Bearer Token JWT
Cara kirim kredensial Setiap request Hanya saat login Hanya saat login
Apa yang dikirim per request Username:Password (Base64) Token opaque (string acak) Token berisi data (self-contained)
Butuh query DB per request? Ya (verifikasi password) Ya (cari token) Tidak
Bisa di-revoke? Ya (ganti password) Ya (hapus dari DB) Sulit (harus tunggu exp)
Membawa data pengguna? Tidak Tidak Ya
Kompleksitas implementasi Sangat mudah Sedang Lebih kompleks
Cocok untuk microservices? Tidak Kurang Ya
Keamanan (dengan HTTPS) Cukup Baik Baik

Ilustrasi Visual Alur Masing-masing

BASIC AUTH — Setiap request membawa password
─────────────────────────────────────────────
Klien ──[username:pass]──► Server ──[cek DB]──► Response
Klien ──[username:pass]──► Server ──[cek DB]──► Response
Klien ──[username:pass]──► Server ──[cek DB]──► Response


BEARER TOKEN — Login sekali, gunakan token
─────────────────────────────────────────────
Klien ──[login]──────────► Server ──[buat token]──► Simpan ke DB
Klien ◄──────────────────── [token: "abc123"]
Klien ──[token: "abc123"]──► Server ──[cek DB]──► Response
Klien ──[token: "abc123"]──► Server ──[cek DB]──► Response


JWT — Login sekali, verifikasi mandiri
─────────────────────────────────────────────
Klien ──[login]──────────► Server ──[buat JWT]──► (tidak disimpan)
Klien ◄──────────────────── [JWT: "eyJ..."]
Klien ──[JWT: "eyJ..."]──► Server ──[verifikasi signature]──► Response
Klien ──[JWT: "eyJ..."]──► Server ──[verifikasi signature]──► Response
                                    (tanpa query DB!)

7. Kapan Menggunakan Masing-masing?

Gunakan Basic Authentication jika:

  • Membangun internal tool atau script otomasi yang tidak berhubungan langsung dengan pengguna akhir
  • Proyek sangat kecil atau prototype yang akan dibuang nanti
  • Membutuhkan implementasi tercepat untuk testing API
  • Tidak ada kebutuhan untuk "logout" atau sesi yang bisa dikelola

Contoh nyata: Mengakses GitHub API dari script CI/CD internal, atau mengakses API sederhana di jaringan lokal yang sudah terlindungi.

Gunakan Bearer Token (Opaque) jika:

  • Kebutuhan untuk merevoke akses secara instan sangat penting (misalnya sistem keuangan, layanan sensitif)
  • Aplikasi tidak terdistribusi — semua layanan mengakses satu database yang sama
  • Ingin mengetahui kapan dan dari mana setiap token digunakan (audit trail per token)
  • Sistem yang tidak membutuhkan skalabilitas tinggi

Contoh nyata: Aplikasi perbankan mobile yang harus bisa mencabut akses token secara instan jika terdeteksi aktivitas mencurigakan.

Gunakan JWT jika:

  • Membangun microservices atau sistem terdistribusi di mana banyak layanan perlu memverifikasi identitas
  • Butuh skalabilitas tinggi — tidak mau query database untuk setiap request
  • Perlu menyematkan informasi konteks (role, izin, data profil) langsung di token agar layanan downstream tidak perlu lookup tambahan
  • Menggunakan arsitektur Single Sign-On (SSO) atau OAuth 2.0

Contoh nyata: Platform e-commerce dengan layanan terpisah (katalog, keranjang, pembayaran, notifikasi) yang masing-masing perlu tahu siapa pengguna dan apa izinnya.

8. Praktik Terbaik Keamanan

Untuk Semua Metode

1. Selalu Gunakan HTTPS

Tanpa HTTPS, semua metode otentikasi di atas bisa dicuri dengan mudah melalui man-in-the-middle attack. HTTPS bukan pilihan — ini wajib.

2. Hindari Menyimpan Kredensial Sensitif di Log

// ❌ JANGAN lakukan ini
console.log('Request headers:', req.headers); // Akan mencetak token ke log!

// ✅ Lakukan ini
console.log('Request dari pengguna:', req.pengguna.id);

3. Tangani Error dengan Pesan yang Tidak Informatif untuk Penyerang

// ❌ Terlalu informatif untuk penyerang
res.status(401).json({ error: 'Password salah untuk user [email protected]' });

// ✅ Lebih aman
res.status(401).json({ error: 'Kredensial tidak valid' });

Khusus Basic Auth

  • Wajib HTTPS — tidak ada pengecualian
  • Gunakan hanya untuk komunikasi server-ke-server yang terkontrol
  • Implementasikan rate limiting untuk mencegah brute-force

Khusus Bearer Token

  • Simpan token di httpOnly cookie (lebih aman dari localStorage yang rentan XSS)
  • Implementasikan token rotation — perbarui token secara berkala
  • Simpan hash token di database, bukan plaintext
  • Implementasikan batas waktu sesi yang tidak aktif

Khusus JWT

Gunakan algoritma yang benar:

// ❌ JANGAN gunakan "none" sebagai algoritma
jwt.sign(payload, '', { algorithm: 'none' }); // Celah keamanan besar!

// ❌ Hindari HS256 untuk sistem besar (kunci simetris)
jwt.sign(payload, secretKey, { algorithm: 'HS256' });

// ✅ Gunakan RS256 untuk sistem yang butuh kunci publik/privat
jwt.sign(payload, privateKey, { algorithm: 'RS256' });

Jangan simpan data sensitif di payload:

// ❌ JANGAN
const payload = {
  sub: userId,
  password: userPassword,    // JANGAN!
  kartuKredit: '4111...',   // JANGAN!
};

// ✅ Lakukan
const payload = {
  sub: userId,
  email: userEmail,          // OK
  role: 'admin',             // OK
  exp: Math.floor(Date.now() / 1000) + 3600
};

Validasi semua klaim dengan ketat:

jwt.verify(token, kunci, {
  algorithms: ['RS256'],      // Tentukan algoritma secara eksplisit
  issuer: 'auth.contoh.com', // Verifikasi issuer
  audience: 'api.contoh.com', // Verifikasi audience
  clockTolerance: 10          // Toleransi 10 detik untuk perbedaan jam server
});

9. Kesimpulan

Setelah membaca panduan ini, kamu sudah memahami tiga metode otentikasi API yang paling umum digunakan:

Basic Authentication adalah yang paling sederhana — cocok untuk penggunaan internal dan testing, tapi kredensial dikirim setiap request sehingga risikonya lebih tinggi.

Bearer Token menawarkan keamanan yang lebih baik karena password hanya dikirim saat login. Token bisa direvoke kapan saja, namun membutuhkan query database di setiap request.

JWT adalah solusi paling modern dan skalabel — token "berbicara sendiri" sehingga tidak butuh database per request. Ideal untuk microservices dan sistem besar, namun butuh kehati-hatian dalam implementasi.

Rekap Singkat

Butuh yang paling simple?          → Basic Auth (dengan HTTPS!)
Butuh bisa revoke kapan saja?      → Bearer Token
Butuh skalabilitas & microservice? → JWT

Apa yang Harus Dipelajari Selanjutnya?

Setelah memahami dasar-dasar ini, topik berikutnya yang relevan untuk dikuasai adalah:

  • OAuth 2.0 — framework otorisasi standar yang biasanya menggunakan JWT di dalamnya
  • OpenID Connect (OIDC) — lapisan identitas di atas OAuth 2.0
  • API Key — metode sederhana untuk mengidentifikasi aplikasi (bukan pengguna)
  • mTLS (Mutual TLS) — otentikasi dua arah untuk komunikasi service-to-service
  • PKCE — ekstensi OAuth 2.0 untuk aplikasi mobile dan SPA

Artikel ini ditulis untuk membantu developer memahami konsep otentikasi API dari dasar hingga siap implementasi. Selalu ikuti praktik terbaik keamanan dan sesuaikan metode yang dipilih dengan kebutuhan aplikasimu.

Share this article

Related Articles

Continue reading with these related posts