Episode ini membahas keamanan akses di Vue: pattern autentikasi client-side, penyimpanan token dan refresh flow, route guards untuk halaman terproteksi, serta role-based access control yang membatasi UI sesuai hak akses pengguna.

Sebagian besar aplikasi punya area yang tidak boleh diakses semua orang: dashboard admin, halaman profil, atau riwayat transaksi. Mengelola siapa yang boleh masuk dan apa yang boleh dilihat setelah masuk adalah pekerjaan authentication dan authorization.
Episode 12 membahas pattern autentikasi client-side di Vue: alur login yang menyimpan state user, penyimpanan token beserta refresh flow untuk request yang aman, route guards untuk melindungi halaman, dan role-based access control agar UI menyesuaikan hak akses pengguna.
Jadikan status login state global yang bisa diakses semua komponen:
import { ref, computed } from "vue";
const user = ref(null);
const token = ref("");
export function useAuth() {
const isLogin = computed(() => !!user.value);
function setAuth(data) {
user.value = data.user;
token.value = data.token;
}
function logout() {
user.value = null;
token.value = "";
}
return { user, token, isLogin, setAuth, logout };
}useAuth() menyimpan user dan token di module scope sehingga state bersama semua komponen. setAuth(data) dipanggil setelah login sukses dan logout() membersihkan semuanya.
Halaman login memanggil API, lalu menyimpan hasilnya:
<script setup>
import { reactive } from "vue";
import { useAuth } from "../composables/useAuth";
import { useRouter } from "vue-router";
const form = reactive({ email: "", password: "" });
const { setAuth } = useAuth();
const router = useRouter();
async function masuk() {
const res = await fetch("/api/login", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(form),
});
const data = await res.json();
setAuth(data);
router.push("/dashboard");
}
</script>setAuth(data) menyimpan user dan token ke composable. Navigasi ke halaman terproteksi dilakukan lewat router.push setelah login sukses.
Token JWT sebaiknya disimpan di memory, bukan localStorage, agar tidak mudah dibaca script jahat. Untuk tetap login saat refresh halaman, gabungkan dengan cookie httpOnly yang dikelola server:
memory: token aktif untuk request API
cookie httpOnly: refresh token untuk sesi panjang
localStorage: hindari kecuali token non-sensitifCookie berflag httpOnly hanya bisa dibaca server, sehingga risiko token dicuri lewat XSS berkurang drastis.
Saat token kedaluwarsa, kirim refresh token dan ulangi request yang gagal:
npm install axiosimport axios from "axios";
const api = axios.create({ baseURL: "/api" });
api.interceptors.response.use(
(res) => res,
async (error) => {
const original = error.config;
if (error.response.status === 401 && !original._retry) {
original._retry = true;
const { data } = await axios.post("/api/refresh");
api.defaults.headers.common.Authorization = `Bearer ${data.token}`;
return api(original);
}
return Promise.reject(error);
}
);interceptors.response.use(...) menangkap respons 401, merefresh token, lalu mengulang request asli lewat api(original). Flag _retry mencegah loop refresh tanpa akhir.
Navigation guard memblokir halaman yang butuh login:
router.beforeEach((to) => {
const { isLogin } = useAuth();
if (to.meta.requiresAuth && !isLogin.value) {
return { name: "login", query: { redirect: to.fullPath } };
}
});to.meta.requiresAuth membaca meta rute. Jika user belum login, guard mengarahkan ke halaman login dengan redirect agar bisa kembali setelah login.
Authorization menentukan apa yang bisa dilihat setelah masuk:
<script setup>
import { useAuth } from "../composables/useAuth";
const { user } = useAuth();
const isAdmin = () => user.value?.role === "admin";
</script>
<template>
<button v-if="isAdmin()">Hapus data</button>
<button v-else>Ajukan permintaan</button>
</template>user.value?.role === "admin" memutuskan elemen mana yang dirender. Role yang sama juga ditegakkan di route meta dan guard, bukan hanya di UI.
Warning
Semua cek di client hanyalah kenyamanan UI. Keamanan sesungguhnya tetap di server: verifikasi token, cek role, dan validasi setiap request. Client yang bisa di-bypass bukanlah pengaman.
Episode 12 membekali kalian pola autentikasi dan otorisasi di Vue: state user lewat composable, penyimpanan token yang aman beserta refresh flow dengan interceptor, route guards untuk halaman terproteksi, dan role-based access control yang membatasi UI.
Inti yang harus dibawa pulang:
useAuth menyimpan user dan token secara global.beforeEach memblokir halaman yang butuh login.Di episode 13 selanjutnya kita membahas API security dan data protection — integrasi API yang aman, pengelolaan environment variables, perlindungan dari CSRF dan XSS, serta cara menangani data sensitif di aplikasi client.