Authentication Basics: Secure User Identity Verification
In this tutorial, you will learn about Authentication Basics: Secure User Identity Verification. We cover key concepts, practical examples, and best practices to help you master this topic.
Authentication verifies that users are who they claim to be. It is the first line of defense for any backend system. Weak authentication is the most common entry point for attackers, responsible for over 80% of web application breaches according to Verizon's Data Breach Investigations Report.
flowchart TB
User[User] --> Register[Register / Sign Up]
User --> Login[Login]
Login --> Validate[Validate Credentials]
Validate -->|Success| Session[Create Session / Token]
Validate -->|Failure| Lockout[Account Lockout Policy]
Session --> Cookie[Set Cookie / Return Token]
Session --> MFA{MFA Enabled?}
MFA -->|Yes| MFACheck[Verify TOTP / SMS / Push]
MFACheck -->|Pass| Authorized[Access Granted]
MFA -->|No| Authorized
What You'll Learn
- Secure password hashing with bcrypt and argon2
- Session-based vs. token-based authentication
- Multi-factor authentication (MFA) concepts
- Account lockout and brute force protection
Why It Matters
Weak authentication is the most common root cause of data breaches. Proper password hashing, session management, and MFA implementation can prevent credential theft, Session Hijacking, and account takeover attacks.
Real-World Use
A healthcare API requires passwordless email links as the primary auth, with TOTP as a second factor for accessing patient records. Passwords are hashed with argon2id. Accounts are locked after 5 failed attempts for 15 minutes.
Secure Authentication Implementation
Password Hashing with bcrypt
const bcrypt = require('bcrypt');
const SALT_ROUNDS = 12;
async function hashPassword(plaintext) {
return bcrypt.hash(plaintext, SALT_ROUNDS);
}
async function verifyPassword(plaintext, hash) {
return bcrypt.compare(plaintext, hash);
}
// Registration
async function registerUser(email, password) {
const hashed = await hashPassword(password);
await db.query('INSERT INTO users (email, password_hash) VALUES (?, ?)', [email, hashed]);
}
Expected output:
Password is hashed with bcrypt (cost factor 12). Hash includes salt automatically. Verification compares plaintext against stored hash.
Session-Based Authentication
const session = require('express-session');
app.use(session({
secret: process.env.SESSION_SECRET,
resave: false,
saveUninitialized: false,
cookie: {
httpOnly: true,
secure: true,
sameSite: 'strict',
maxAge: 24 * 60 * 60 * 1000
}
}));
app.post('/api/login', async (req, res) => {
const { email, password } = req.body;
const [users] = await db.query('SELECT * FROM users WHERE email = ?', [email]);
if (users.length === 0 || !(await verifyPassword(password, users[0].password_hash))) {
return res.status(401).json({ error: 'Invalid credentials' });
}
req.session.userId = users[0].id;
req.session.role = users[0].role;
res.json({ message: 'Login successful' });
});
Expected output:
Session cookie (httpOnly, secure, sameSite) is set on successful login. Session data is stored server-side. Cookie cannot be read by JavaScript.
Brute Force Protection
const rateLimit = require('express-rate-limit');
const loginLimiter = rateLimit({
windowMs: 15 * 60 * 1000,
max: 5,
message: { error: 'Too many login attempts. Try again in 15 minutes.' },
standardHeaders: true,
legacyHeaders: false,
keyGenerator: (req) => req.ip
});
app.post('/api/login', loginLimiter, async (req, res) => {
// Login logic
});
Expected output:
After 5 failed login attempts in 15 minutes, the IP is blocked. Response includes Retry-After header.
Common Mistakes
- Storing passwords with MD5, SHA1, or unsalted hashes. Use bcrypt or argon2id.
- Not enforcing password complexity requirements (minimum length, character types).
- Using HTTP-only sessions without secure flag, exposing session cookies to interception.
- Not implementing account lockout or Rate Limiting on login endpoints.
- Returning different error messages for "user not found" vs. "wrong password" — this leaks user existence information.
Practice Questions
- Why is bcrypt preferred over SHA-256 for password hashing?
- What is the difference between session-based and token-based authentication?
- What does the httpOnly cookie flag do?
- Why should error messages for login failures be generic?
- How does MFA improve authentication security?
Challenge
Build a secure authentication system with: bcrypt password hashing, rate-limited login endpoint (5 attempts per 15 minutes), session management with httpOnly cookies, and a generic error message for failed logins.
FAQ
Mini Project
Build a complete authentication API with registration, login, logout, and profile endpoints. Implement bcrypt hashing, httpOnly sessions, rate-limited login, and a generic error response. Add tests for: successful login, failed login (wrong password and rate limit), and session persistence.
What's Next
Continue to Authorization to learn how to control access to resources after authentication.
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro