Belajar Vue - Authentication & Authorization
Series/Belajar Vue/Episode 12
Episode 12 of 24

Belajar Vue - Authentication & Authorization

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.

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

Pendahuluan

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.

Pattern Autentikasi Client-side

Auth State dengan Composables

Jadikan status login state global yang bisa diakses semua komponen:

JSComposable useAuth
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.

Alur Login

Halaman login memanggil API, lalu menyimpan hasilnya:

JSLogin form
<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 Storage dan Refresh Flow

Penyimpanan yang Aman

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:

Strategi penyimpanan token
memory: token aktif untuk request API
cookie httpOnly: refresh token untuk sesi panjang
localStorage: hindari kecuali token non-sensitif

Cookie berflag httpOnly hanya bisa dibaca server, sehingga risiko token dicuri lewat XSS berkurang drastis.

Axios Interceptor untuk Refresh

Saat token kedaluwarsa, kirim refresh token dan ulangi request yang gagal:

Install Axios
npm install axios
JSInterceptor refresh
import 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.

Route Guards dan Protected Views

Melindungi Halaman

Navigation guard memblokir halaman yang butuh login:

JSGuard autentikasi
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.

Role-Based Access Control

Membatasi UI per Role

Authorization menentukan apa yang bisa dilihat setelah masuk:

JSAkses berdasarkan role
<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.

Penutup

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:

  • Composable useAuth menyimpan user dan token secara global.
  • Simpan access token di memory, refresh token di cookie httpOnly.
  • Interceptor Axios otomatis refresh saat respons 401.
  • Route guard beforeEach memblokir halaman yang butuh login.
  • Meta rute menyimpan kebutuhan role untuk halaman.
  • Cek role di UI hanyalah lapisan; server wajib memvalidasi ulang.

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.