
What is User Authentication?
User authentication is the process of confirming that someone is who they claim to be when accessing a system or application. It acts as the first line of defence to protect your application’s data, privacy, and core functionalities. Without proper authentication, unauthorised users might gain access to sensitive information, potentially leading to data breaches or malicious actions.
💡 Learn more about OWASP’s top web security risks.
Why Use JWT (JSON Web Token) for Authentication?
JWT (JSON Web Token) is a widely adopted standard for implementing stateless authentication in modern web applications. It allows secure transmission of information between parties as a JSON object that is digitally signed.
Key Advantages of JWT
- Stateless Sessions — JWT tokens are self-contained and don’t require server-side session storage, making scaling easier.
- Scalability — Perfect for distributed systems, microservices, and cloud-native apps.
- Security — Supports digital signatures (HMAC or RSA) and optional encryption for added safety.
- Performance — Reduces server-side processing as token validation doesn’t rely on session lookups.
💡 Explore the JWT official documentation for deeper technical details.
Step-by-Step Guide: Implementing JWT Authentication
👉 Need expert assistance with authentication? Check out our Custom Software Development Services.
1. Backend Setup (Node.js + Express)
Install Required Packages
npm install express mongoose bcryptjs jsonwebtoken dotenv cors
Create the User Model
// models/User.js
const mongoose = require('mongoose');
const UserSchema = new mongoose.Schema({
name: String,
email: { type: String, required: true, unique: true },
password: { type: String, required: true }
});
module.exports = mongoose.model('User', UserSchema);
Registration Endpoint
// routes/auth.js
const router = require('express').Router();
const bcrypt = require('bcryptjs');
const jwt = require('jsonwebtoken');
const User = require('../models/User');
router.post('/register', async (req, res) => {
const { name, email, password } = req.body;
try {
const existingUser = await User.findOne({ email });
if (existingUser) return res.status(400).json({ error: 'User already exists' });
const hashedPassword = await bcrypt.hash(password, 10);
const user = await User.create({ name, email, password: hashedPassword });
res.status(201).json({ message: 'User registered successfully' });
} catch (err) {
res.status(500).json({ error: 'Registration failed' });
}
});
Login Endpoint
router.post('/login', async (req, res) => {
const { email, password } = req.body;
try {
const user = await User.findOne({ email });
if (!user) return res.status(400).json({ error: 'Invalid credentials' });
const isMatch = await bcrypt.compare(password, user.password);
if (!isMatch) return res.status(400).json({ error: 'Invalid credentials' });
const token = jwt.sign({ id: user._id }, process.env.JWT_SECRET, { expiresIn: '1h' });
res.json({
token,
user: { id: user._id, name: user.name, email: user.email }
});
} catch (err) {
res.status(500).json({ error: 'Login failed' });
}
});
Protect Routes with Middleware
// middleware/authenticateToken.js
const jwt = require('jsonwebtoken');
const authenticateToken = (req, res, next) => {
const token = req.header('Authorization')?.split(' ')[1];
if (!token) return res.status(401).json({ error: 'Access denied' });
try {
const verified = jwt.verify(token, process.env.JWT_SECRET);
req.user = verified;
next();
} catch (err) {
res.status(400).json({ error: 'Invalid token' });
}
};
module.exports = authenticateToken;
2. Frontend Setup (React)
Install Axios
npm install axios
Create Login Component
import axios from 'axios';
import { useState } from 'react';
function Login() {
const [email, setEmail] = useState('');
const [password, setPassword] = useState('');
const handleSubmit = async (e) => {
e.preventDefault();
try {
const res = await axios.post('/api/login', { email, password });
localStorage.setItem('token', res.data.token);
alert('Login successful');
} catch (err) {
alert('Login failed');
}
};
return (
<form onSubmit={handleSubmit}>
<input type="email" value={email} onChange={(e) => setEmail(e.target.value)} placeholder="Email" required />
<input type="password" value={password} onChange={(e) => setPassword(e.target.value)} placeholder="Password" required />
<button type="submit">Login</button>
</form>
);
}
Access a Protected Route
import { useEffect, useState } from 'react';
import axios from 'axios';
function Dashboard() {
const [user, setUser] = useState(null);
useEffect(() => {
const token = localStorage.getItem('token');
axios.get('/api/protected', {
headers: { Authorization: `Bearer ${token}` }
})
.then(res => setUser(res.data))
.catch(() => alert('Access denied'));
}, []);
return user ? <h1>Welcome {user.name}</h1> : <p>Loading...</p>;
}
Best Practices for Production
- Use HttpOnly cookies instead of localStorage for storing tokens to protect against XSS.
- Always use HTTPS to secure data in transit and prevent MITM attacks.
- Implement refresh tokens for long-lived sessions with secure token renewal.
- Sanitise user inputs to prevent injection attacks and XSS exploits.
- Handle token expiry gracefully by prompting re-login or token renewal.
Explore how we secure cloud apps at scale in our Cloud Solutions.
FAQs (Frequently Asked Questions)
- Is JWT secure for user authentication?
Yes. When combined with HTTPS, HttpOnly cookies, and proper expiration policies, JWT provides a secure method for stateless authentication.
- Can JWT be used with React and Node.js together?
Absolutely. React handles the frontend while Node.js manages token generation and verification on the backend.
- How does JWT help with scalability?
JWT’s stateless nature eliminates the need for centralised session storage, making horizontal scaling easier across distributed systems.
Conclusion
Implementing JWT authentication in a React and Node.js full-stack app offers secure, scalable, and efficient identity management. By combining proper token handling, input sanitisation, HTTPS, and refresh mechanisms, you can build a production-grade solution fit for both local and global users.
Ready to enhance your app’s security? Discover our AI/ML and Cloud Development Services.