This episode covers API security in Vue: API integration with environment variables, XSS protection through safe rendering, CSRF protection, handling sensitive data on the client, and best practices for secure API communication.

A frontend application talks to a server every day, and every conversation is an attack surface: data can leak, tokens can be stolen, or the page can be hijacked through injection. Understanding API security isn't optional — it's a requirement for production applications.
Episode 13 covers securing client-server communication in Vue: secure API integration with environment variables, XSS prevention through safe rendering, CSRF protection, how to handle sensitive data in a client application, and best practices for API communication you can apply right away.
Never write API URLs or keys directly in code. Store them in a .env file with the VITE_ prefix:
VITE_API_BASE_URL=https://api.example.com
VITE_APP_VERSION=1.0.0import.meta.env.VITE_API_BASE_URLimport.meta.env.VITE_API_BASE_URL reads the value from .env. Only variables prefixed with VITE_ are exposed to the client; server secrets must never end up in the bundle.
Wrap all API calls in a single module so security policies stay consistent:
const BASE = import.meta.env.VITE_API_BASE_URL;
export async function api(path, options = {}) {
const res = await fetch(`${BASE}${path}`, {
...options,
credentials: "include",
headers: {
"Content-Type": "application/json",
...options.headers,
},
});
if (!res.ok) throw new Error(`HTTP ${res.status}`);
return res.json();
}credentials: "include" sends session cookies to the API domain, and Content-Type is set uniformly. One place to add auth headers, timeouts, or logging.
Vue escapes all interpolation by default, so text from users renders safely:
<script setup>
const komentar = "<script>alert('xss')</script>";
</script>
<template>
<p>{{ komentar }}</p>
</template>{{ komentar }} displays the string as text, not executes it. Never use v-html for user data without sanitizing it, because that injects raw HTML.
If you truly need HTML, sanitize it first with a library:
npm install dompurifyimport DOMPurify from "dompurify";
const bersih = DOMPurify.sanitize(kontenDariServer);DOMPurify.sanitize(...) removes dangerous tags and attributes before they're rendered through v-html. The golden rule: treat all data from outside as untrusted.
CSRF happens when a browser sends session cookies along with a request triggered by a malicious site. The main mitigations in Vue: use cookies set with SameSite by the server, and send an X-CSRF-Token header read from a cookie:
function getCsrfToken() {
const match = document.cookie.match(/csrftoken=([^;]+)/);
return match ? match[1] : "";
}
api.defaults.headers.common["X-CSRF-Token"] = getCsrfToken();document.cookie.match(...) reads the CSRF token from a cookie, then it's sent as a header on every request. The combination of SameSite plus a token makes cross-site attacks much harder.
The main rule: anything that ends up in the JavaScript bundle can be read by users. Never put secrets, API keys, or passwords in frontend files. Use a backend proxy to hide secrets, and only expose the data that truly needs to be shown. Putting a secret in VITE_ doesn't make it safe — it just moves it into the public.
Warning
Client security is a layer, not a wall. Design your API with the assumption that all frontend code can be read and all requests can be replayed.
Episode 13 made your API communication safer: environment variables for configuration, interpolation escaped by default, sanitizing with DOMPurify before v-html, CSRF tokens, plus clear rules for sensitive data and best practices for API communication.
Key takeaways:
VITE_ prefix for variables allowed to be exposed to the client.v-html is dangerous for unsanitized user data.In the next episode 14, we'll cover caching and performance — client-side caching with Vue Query and local storage, memoization with computed and watchEffect, lazy loading components, and how to optimize rendering and reactivity.