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.

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.
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.
Sebelum menulis kode, identifikasi mekanisme yang dipakai aplikasi kalian:
| Mekanisme | Cara pengiriman | Kapan umum dipakai | Perhatian utama di k6 |
|---|---|---|---|
| API key | header X-API-Key | service-to-service, integrasi sederhana | simpan di __ENV, jangan hardcoded |
| JWT bearer | header Authorization: Bearer | SPA dan API modern | token berumur pendek, perlu refresh |
| OAuth2 | alur token, biasanya POST /token | aplikasi enterprise, SSO | token punya expires_in, jangan login berlebihan |
| Sesi cookie | cookie session | aplikasi web tradisional | cookie 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.
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:
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?
Jika aplikasi memakai API key, polanya lebih pendek — tidak perlu setup():
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:
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.
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:
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.
Load test yang baik tidak hanya mengukur jalur sukses. Endpoint yang dilindungi seharusnya ditest juga dari sisi negatif:
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.
setup() untuk token panjang umur.__ENV atau data-driven test (episode 8).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:
setup.check pada login mencegah tes mengukur response error.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!