The "qwerty123" Password No Longer Works: Why Security Isn't Boring
Imagine: you've written a cool web application. A beautiful interface, reactive code, everything runs smoothly. You launch it, register the first user — and an hour later your database leaks into the public domain. Sound familiar? Unfortunately, secure authentication in JavaScript is a topic many developers put off until later. And that's a mistake.
In this article, we'll break down how to protect your application from the most common attacks: token interception, XSS, CSRF, and password leaks. We won't lecture you about "doing things right" — we'll show you code you can use right now.
Ready? Let's go.
Authentication in JavaScript: Why the Client is a Battlefield
When we talk about authentication on the web, we often think about the backend: databases, sessions, hashing. But JavaScript authentication starts on the client. And that's where the pitfalls lie.
Everything that runs in the browser can be read, modified, or stolen. Your JavaScript code is an open book to an attacker if they find a vulnerability. Therefore, the first rule of secure authentication is: never trust the client. Never.
Main Threats on the Client Side
- XSS (Cross-Site Scripting) — an attacker injects a script that steals tokens from localStorage.
- CSRF (Cross-Site Request Forgery) — the user is authenticated, and a malicious site sends requests on their behalf.
- Man-in-the-Middle — traffic interception if HTTPS is not used.
- Password Leakage — sending a password in plain text or storing it in code.
Sounds scary? In reality, protecting against this isn't that difficult. The main thing is knowing which tools to use.
JWT: Convenient, But with a Catch
JWT (JSON Web Token) is a standard for creating access tokens. It's lightweight, doesn't require server-side storage, and is perfect for SPAs. But its popularity makes it a target.
Many developers store JWT in localStorage. This is a mistake. localStorage is accessible from any JavaScript code on the page. If you have even one XSS vulnerability — the token is stolen.
How to Store JWT Correctly
The best way is httpOnly cookies. Cookies with the httpOnly flag are inaccessible to JavaScript. XSS won't steal them. But there's a nuance: cookies are automatically sent with every request, making the application vulnerable to CSRF. The solution is to use SameSite and CSRF tokens.
Here's an example of setting an httpOnly cookie on the backend (Node.js with Express):
// Server (Node.js / Express)res.cookie('token', jwtToken, { httpOnly: true, // Inaccessible to JavaScript secure: true, // HTTPS only sameSite: 'strict', // CSRF protection maxAge: 3600000 // 1 hour});On the client, you simply send requests — the cookies will be attached automatically:
// Client (JavaScript)fetch('/api/profile', { method: 'GET', credentials: 'include' // Mandatory!}).then(res => res.json()).then(data => console.log(data));Note: credentials: 'include' — without this, cookies won't be sent to a different origin.
Password Hashing: bcrypt to the Rescue
Storing passwords in plain text is like leaving your house keys under the doormat. Even if your site is hacked, the passwords should be useless to the attacker.
bcrypt is a hashing algorithm specifically designed to be slow. Because hashing a password for a user takes a fraction of a second, but cracking it takes years. In JavaScript (Node.js), use the b