In this blog, we will walk through creating a full-stack dashboard application that includes user registration, login, and a protected dashboard using Redux Toolkit. The backend will be built with Express.js and MongoDB, while the frontend will leverage Redux Toolkit for state management.
server.js
const express = require('express'); const mongoose = require('mongoose'); const dotenv = require('dotenv'); const cors = require('cors'); const bodyParser = require('body-parser'); const authRoutes = require('./routes/auth'); // Import the authentication routes dotenv.config(); const app = express(); app.use(cors()); app.use(bodyParser.json()); const PORT = process.env.PORT || 5000; // Connect to MongoDB mongoose.connect(process.env.MONGO_URI, { useNewUrlParser: true, useUnifiedTopology: true, }) .then(() => app.listen(PORT, () => console.log(`Server running on port ${PORT}`))) .catch((error) => console.log(`${error} did not connect`)); // Mount the authentication routes app.use('/api/auth', authRoutes); // Base path for the authentication routes // Test route to ensure the API is running app.get('/', (req, res) => res.send('API is running...'));
Model/User.js
const mongoose = require('mongoose'); const bcrypt = require('bcryptjs'); const userSchema = new mongoose.Schema({ username: { type: String, required: true, unique: true }, email: { type: String, required: true, unique: true }, password: { type: String, required: true }, }); userSchema.pre('save', async function(next) { if (!this.isModified('password')) return next(); this.password = await bcrypt.hash(this.password, 10); next(); }); module.exports = mongoose.model('User', userSchema);
routes/auth.js
const express = require('express'); const User = require('../models/User'); const jwt = require('jsonwebtoken'); const bcrypt = require('bcryptjs'); const router = express.Router(); const { body, validationResult } = require('express-validator'); const generateToken = (id) => { return jwt.sign({ id }, process.env.JWT_SECRET, { expiresIn: '1d' }); }; // Register router.post('/register', async (req, res) => { const { username, email, password } = req.body; try { const existingUser = await User.findOne({ email }); if (existingUser) return res.status(400).json({ message: 'User already exists' }); const user = await User.create({ username, email, password }); const token = generateToken(user._id); // Exclude password from the response const { password: _, ...userWithoutPassword } = user.toObject(); res.status(201).json({ user: userWithoutPassword, token }); } catch (error) { res.status(500).json({ message: 'Something went wrong' }); } }); // Login router.post('/login', async (req, res) => { const { email, password } = req.body; try { const user = await User.findOne({ email }).select('+password'); // Explicitly include password for comparison if (!user) return res.status(404).json({ message: 'User not found' }); const isPasswordCorrect = await bcrypt.compare(password, user.password); if (!isPasswordCorrect) return res.status(400).json({ message: 'Invalid credentials' }); const token = generateToken(user._id); // Exclude password from the response const { password: _, ...userWithoutPassword } = user.toObject(); res.status(200).json({ user: userWithoutPassword, token }); } catch (error) { res.status(500).json({ message: 'Something went wrong' }); } }); module.exports = router;
.env
MONGO_URI=mongodb://localhost:27017/redux-auth-system JWT_SECRET=your_jwt_secret
Now Redux-Toolkit
Here’s a complete front-end implementation using React and Redux for an authentication system with protected routes. This includes login, registration, and navigation, with protection for routes like Dashboard
and My Account
.
1. Install Required Dependencies
Install the required libraries:
2. Folder Structure
Create the following folder structure:
3. authSlice.js
(Redux Slice for Authentication)
This slice manages the authentication state, including user login, logout, and registration.
4. store.js
(Redux Store)
Set up the Redux store to include the authSlice
.
5. ProtectedRoute Component
This component ensures only authenticated users can access protected routes.
6. Navbar Component
The navigation bar updates based on whether the user is logged in.
7. Login Component
Handles user login.
8. Register Component
Handles user registration.
9. Dashboard Component
Protected dashboard view.
10. My Account Component
Protected account page.
11. App Component
Integrates everything together.
import React from 'react'; import { BrowserRouter as Router, Routes, Route } from 'react-router-dom'; import Navbar from './components/Navbar'; import Login from './components/Login'; import Register from './components/Register'; import Dashboard from './components/Dashboard'; import MyAccount from './components/MyAccount'; import ProtectedRoute from './components/ProtectedRoute'; const App = () => { return ( <Router> <Navbar /> <Routes> <Route path="/" element={<h2>Welcome to Redux Auth App</h2>} /> <Route path="/login" element={<Login />} /> <Route path="/register" element={<Register />} /> <Route path="/dashboard" element={ <ProtectedRoute> <Dashboard /> </ProtectedRoute> } /> <Route path="/my-account" element={ <ProtectedRoute> <MyAccount /> </ProtectedRoute> } /> </Routes> </Router> ); }; export default App;