Belajar k6 - Otentikasi, Otorisasi & Access Control
Series/Belajar k6/Episode 11
Episode 11 of 19

Belajar k6 - Otentikasi, Otorisasi & Access Control

Menghadirkan alur otentikasi nyata ke dalam load test: memilih pendekatan OAuth2, JWT, API key, atau sesi berbasis cookie, melakukan login untuk memperoleh token, memakainya sebagai bearer token pada permintaan berikutnya, hingga memperbarui refresh token di tengah skenario yang berjalan lama.

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

Pendahuluan

Di episode 10 kalian sudah menembus lapisan jaringan — TLS, redirect, sampai WebSocket. Tapi kebanyakan API yang layak diuji tidak langsung membuka pintunya: ada gerbang otentikasi di depan. Kalau load test kalian hanya menyentuh endpoint publik, kalian mengukur jalan masuk belakang, bukan perjalanan yang sebenarnya dilalui pengguna. Pengguna membuka aplikasi, login, lalu memakai fitur — dan beban login serta validasi token itu bagian dari pengalaman mereka.

Episode ini menjawab pertanyaan yang selama ini menggantung: bagaimana caranya berotentikasi di dalam k6? Kita akan memilih mekanisme yang tepat (OAuth2, JWT, API key, sesi cookie), meniru alur login hingga memakai token, lalu memecahkan masalah yang paling sering membuat load test bohong: token yang kedaluwarsa di tengah skenario panjang.

Pembahasan Utama

Mengapa Load Test Harus Meniru Alur Otentikasi

Ada dua kesalahan yang sering dilakukan: menghindari endpoint yang dilindungi, atau meniru token secara asal-asalan. Keduanya menguji aplikasi yang berbeda dari yang dipakai pengguna nyata. Endpoint yang butuh autentikasi biasanya memuat middleware auth, session store, dan database lookup — kode yang ikut menentukan latensi. Tanpa memuat alur ini, hasil tes kalian terlalu bagus dan tidak berguna untuk perencanaan kapasitas.

Sebaliknya, jangan juga meng-copy token dari browser dan menaruhnya sebagai konstanta di script. Token itu akan kedaluwarsa, dan yang lebih penting: kalian tidak sedang mengukur alur login yang nyata. Kunci keseimbangannya: login dengan cara yang benar, sesering yang diperlukan, tidak lebih.

Memilih Mekanisme Otentikasi

Sebelum menulis kode, identifikasi mekanisme yang dipakai aplikasi kalian:

MekanismeCara pengirimanKapan umum dipakaiPerhatian utama di k6
API keyheader X-API-Keyservice-to-service, integrasi sederhanasimpan di __ENV, jangan hardcoded
JWT bearerheader Authorization: BearerSPA dan API moderntoken berumur pendek, perlu refresh
OAuth2alur token, biasanya POST /tokenaplikasi enterprise, SSOtoken punya expires_in, jangan login berlebihan
Sesi cookiecookie sessionaplikasi web tradisionalcookie otomatis dikirim jika pakai jar

Aturannya sederhana: lakukan login paling tidak sesering yang dilakukan pengguna nyata. Jika token berlaku satu jam dan skenario tes berjalan 30 menit, satu kali login di setup() sudah mewakili pengguna. Jika token berlaku 5 menit, kalian harus meniru proses refresh di tengah skenario — bagian yang sering dilupakan dan justru paling realistis.

Login Sekali, Token Dipakai Semua VU: pola setup

k6 mengeksekusi setup() sekali sebelum VU mulai berjalan, dan hasilnya diteruskan ke fungsi iterasi. Ini tempat paling tepat untuk login: satu panggilan login, lalu token dibagikan ke semua VU. Cocok untuk token yang cukup panjang umurnya:

auth-setup.js — login sekali, token untuk semua VU
import http from "k6/http";
import { check } from "k6";
 
const BASE_URL = __ENV.BASE_URL || "https://api.example.com";
 
export function setup() {
    const loginRes = http.post(`${BASE_URL}/oauth/token`, {
        grant_type: "password",
        username: __ENV.TEST_USER,
        password: __ENV.TEST_PASSWORD,
    });
    check(loginRes, { "login sukses": (r) => r.status === 200 });
    return loginRes.json();
}
 
export default function (auth) {
    const params = {
        headers: {
            Authorization: `Bearer ${auth.access_token}`,
        },
    };
    const res = http.get(`${BASE_URL}/me`, params);
    check(res, { "profil dapat diakses": (r) => r.status === 200 });
}

Perhatikan pola dua lapis yang tidak boleh dilupakan:

  • check(loginRes, ...) — jika login gagal, seluruh tes mengukur response error, bukan aplikasi. Check ini menjadi alarm dini.
  • return loginRes.json() — nilai yang dikembalikan setup() otomatis tersedia sebagai argumen fungsi default. Semua VU berbagi objek ini tanpa mengulang login.

Satu login untuk semua VU juga berarti satu akun uji. Dengan puluhan ribu request dalam beberapa menit, akun itu akan menimbulkan beban login yang tidak realistis jika setiap VU login sendiri. Ini bukan bug — ini keputusan desain: seberapa sering pengguna nyata melakukan login dalam periode itu?

API Key: Variasi Paling Sederhana

Jika aplikasi memakai API key, polanya lebih pendek — tidak perlu setup():

auth-apikey.js — API key via header
import http from "k6/http";
import { check } from "k6";
 
const params = {
    headers: {
        "X-API-Key": __ENV.API_KEY,
    },
};
 
export default function () {
    const res = http.get("https://api.example.com/v1/orders", params);
    check(res, { "orders terautentikasi": (r) => r.status === 200 });
}

Nilai kunci di sini adalah __ENV.API_KEY — kita bedah alasan keamanannya secara mendalam di episode 12. Untuk sekarang, ingat aturannya: kredensial nyata tidak pernah masuk ke file script.

Aplikasi web tradisional biasanya memakai sesi berbasis cookie. K6 punya cookie jar per VU yang otomatis menyimpan dan mengirim cookie: login sekali di awal iterasi, dan request berikutnya membawa cookie tanpa perlu mengatur header manual:

auth-cookie.js — sesi berbasis cookie
import http from "k6/http";
import { check } from "k6";
 
export default function () {
    const loginRes = http.post("https://app.example.com/login", {
        username: __ENV.TEST_USER,
        password: __ENV.TEST_PASSWORD,
    });
    check(loginRes, { "login dengan sesi sukses": (r) => r.status === 200 });
 
    const profilRes = http.get("https://app.example.com/me");
    check(profilRes, { "cookie dikirim otomatis": (r) => r.status === 200 });
}

Karena setiap VU punya cookie jar sendiri, sesi antar VU terisolasi — ini penting: satu VU tidak boleh mewarisi sesi VU lain, karena itu akan mengacaukan metrik. Jar juga di-reset di akhir iterasi, sehingga setiap iterasi mewakili pengguna yang baru login. Jika aplikasi kalian memperpanjang sesi dengan cookie yang dikirim ulang (rolling session), pertimbangkan noCookiesReset untuk skenario pengguna yang sudah lama online.

Refresh Token di Tengah Skenario Panjang

Inilah masalah yang paling sering membuat load test menghasilkan data yang menyesatkan: access token (misalnya JWT) kedaluwarsa dalam hitungan menit, tapi skenario berjalan setengah jam. Tanpa penanganan, response 401 meracuni metrik — dan kalian akan menyimpulkan "aplikasi error 401 di menit ke-25" padahal itu perilaku token, bukan bug aplikasi.

Pola yang benar: deteksi 401, perbarui token, ulangi request. Karena token dibagikan lintas VU, perbaruan dilakukan di dalam iterasi yang menemukan 401:

auth-refresh.js — perbarui token di tengah skenario
import http from "k6/http";
import { check, sleep } from "k6";
 
const BASE_URL = __ENV.BASE_URL || "https://api.example.com";
 
export function setup() {
    const loginRes = http.post(`${BASE_URL}/login`, {
        username: __ENV.TEST_USER,
        password: __ENV.TEST_PASSWORD,
    });
    return loginRes.json();
}
 
export default function (auth) {
    let token = auth.access_token;
    let refreshToken = auth.refresh_token;
 
    for (let i = 0; i < 10; i++) {
        const res = http.get(`${BASE_URL}/dashboard`, {
            headers: { Authorization: `Bearer ${token}` },
        });
 
        if (res.status === 401) {
            const refreshed = http.post(`${BASE_URL}/refresh`, {
                refresh_token: refreshToken,
            });
            check(refreshed, { "refresh token diterima": (r) => r.status === 200 });
            const body = refreshed.json();
            token = body.access_token;
            refreshToken = body.refresh_token || refreshToken;
        } else {
            check(res, { "dashboard OK": (r) => r.status === 200 });
        }
        sleep(5);
    }
}

Dengan pola ini, load test mengukur perilaku nyata: token memang kedaluwarsa di tengah jalan, aplikasi harus merefresh, dan itu bagian dari pengalaman pengguna. Jika server refresh-nya lambat atau gagal di bawah beban, kalian akan melihatnya — justru itulah temuan yang berharga. Ingat pula untuk mengukur berapa sering 401 muncul; jika jauh lebih sering dari yang seharusnya, itu sinyal konfigurasi token (masa berlaku, skew jam, atau waktu server) yang perlu diselidiki.

Validasi Akses dan Error Handling Endpoint yang Dilindungi

Load test yang baik tidak hanya mengukur jalur sukses. Endpoint yang dilindungi seharusnya ditest juga dari sisi negatif:

  • Request tanpa token seharusnya menangkap 401, bukan 200 — kalau 200, otorisasi bocor.
  • Request dengan token yang tidak punya hak akses seharusnya menangkap 403.
  • Pastikan error handling di script tidak menyembunyikan masalah: check status yang diharapkan secara eksplisit, dan jangan biarkan kode memakai token expired tanpa verifikasi.

Pola terbaik: buat iterasi yang memverifikasi otorisasi sebagai bagian dari alur, dengan tag khusus (misal endpoint: "me"), sehingga di dashboard nanti kalian bisa membandingkan latensi dan error rate per endpoint yang dilindungi. Menguji jalur akses yang benar dan yang salah adalah cara kalian memastikan tes tidak hanya mengukur kecepatan, tapi juga keamanan yang masih berfungsi di bawah beban.

Pitfalls yang Sering Ditemui

  1. Login di setiap iterasi — mengubah beban: tes berubah menjadi tes auth server. Gunakan setup() untuk token panjang umur.
  2. Token di-hardcode dari browser — kedaluwarsa, dan kalian tidak mengukur alur login. Selalu login di script.
  3. Mengabaikan 401 — metrik tercemar error yang bukan bug aplikasi. Terapkan refresh atau perpanjang masa berlaku token uji.
  4. Memakai satu akun untuk ribuan VU — rate limit atau lockout akun bisa terjadi. Siapkan beberapa akun uji dan rotasi lewat __ENV atau data-driven test (episode 8).

Penutup

Pada episode 11 ini kalian telah mampu menghadirkan otentikasi nyata ke dalam load test: memilih mekanisme yang tepat di antara API key, JWT bearer, OAuth2, dan sesi cookie, memakai setup() untuk login sekali dan membagikan token ke semua VU, membiarkan cookie jar menangani sesi otomatis, menerapkan pola refresh token di tengah skenario panjang, dan memvalidasi baik jalur akses yang benar maupun yang salah.

Inti yang harus kalian bawa:

  • Login sesering pengguna nyata, tidak lebih — token panjang umur cukup di-setup.
  • check pada login mencegah tes mengukur response error.
  • Token yang kedaluwarsa bukan bug aplikasi; tangani dengan refresh, jangan biarkan meracuni metrik.
  • Uji juga jalur negatif: 401 dan 403 adalah perilaku yang sah dan harus tetap benar di bawah beban.

Mulai episode berikutnya, kita berurusan dengan hal yang lebih serius. Setiap token dan kredensial yang kalian pegang di script sekarang adalah aset yang harus dilindungi. Di episode 12 kita akan membahas Keamanan Testing & Best Practice — bagaimana memastikan tes kalian tidak menghancurkan aturan keamanan aplikasi, menangani secret dengan benar, dan menghormati lingkungan produksi. Sampai jumpa di episode 12!

Belajar k6 - Otentikasi, Otorisasi & Access Control | Belajar k6