DEV Community

Avanexa Technologies
Avanexa Technologies

Posted on

How I Built a Full Authentication System Using React + Node.js

Introduction

Building an authentication system is one of the most important steps in creating a secure web application. It controls how users sign up, log in, and access protected content. When I decided to build a full authentication system using React and Node.js, my goal was to keep it simple, secure, and easy to understand.

This guide shares the approach I followed, along with practical steps that can help you build your own authentication system from scratch.

Understanding the Core Flow

Before writing any code, I focused on the basic flow of authentication. A typical system includes:

User registration

User login

Password protection

Session or token management

Access to protected routes

Understanding this flow made it easier to structure both the frontend and backend.

Setting Up the Backend with Node.js

I started by setting up a Node.js server using Express. This handled all authentication logic and database communication.

After initializing the project, I installed essential packages:

npm install express bcryptjs jsonwebtoken cors dotenv

bcryptjs for password hashing

jsonwebtoken for authentication tokens

cors for handling cross-origin requests

Then I created a basic server:

const express = require("express");
const app = express();

app.use(express.json());

app.listen(5000, () => console.log("Server running"));

This formed the base for handling authentication routes.

Creating the User Model

Next, I set up a user structure in the database. Each user needed:

Name

Email

Password (hashed)

When a user registers, their password is never stored as plain text. Instead, it is hashed using bcrypt:

const hashedPassword = await bcrypt.hash(password, 10);

This step is essential for security.

Building the Registration Endpoint

The registration route allows new users to create an account.

app.post("/register", async (req, res) => {
const { name, email, password } = req.body;

const hashedPassword = await bcrypt.hash(password, 10);

// Save user to database
res.json({ message: "User registered successfully" });
});

This route collects user data, hashes the password, and stores it securely.

Implementing Login with JWT

Login is where authentication becomes active. After verifying user credentials, I generated a JSON Web Token (JWT):

const token = jwt.sign({ id: user.id }, "secretkey", {
expiresIn: "1h",
});

This token is sent to the client and used for future requests.

The login route checks:

If the user exists

If the password matches

Only then is access granted.

Protecting Routes

To secure certain routes, I created a middleware that verifies the token:

const authMiddleware = (req, res, next) => {
const token = req.headers.authorization;

if (!token) return res.status(401).json({ message: "Unauthorized" });

try {
const verified = jwt.verify(token, "secretkey");
req.user = verified;
next();
} catch {
res.status(400).json({ message: "Invalid token" });
}
};

This ensures only authenticated users can access protected data.

Setting Up the React Frontend

On the frontend, I used React to create simple forms for registration and login.

The login form sends a request to the backend:

const response = await fetch("http://localhost:5000/login", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ email, password }),
});

Once the token is received, I stored it in local storage:

localStorage.setItem("token", data.token);

This allows the user to stay logged in across sessions.

Handling Protected Pages in React

To restrict access to certain pages, I checked whether a token exists before rendering content.

If no token is found, the user is redirected to the login page. This simple check ensures only authenticated users can view protected sections.

Challenges I Faced

One challenge was handling token expiration. If a token expires, users need to log in again. I solved this by checking responses from protected routes and redirecting users when needed.

Another issue was managing state between components. Keeping authentication status consistent across the app required careful handling of local storage and React state.

Best Practices I Followed

To make the system more reliable, I followed a few important practices:

Never store plain-text passwords

Keep secret keys in environment variables

Validate user input on both the frontend and backend

Use HTTPS in production

Separate authentication logic from UI components

These steps helped improve both security and maintainability.

Final Thoughts

Building a full authentication system using React and Node.js gave a clear understanding of how secure user management works. While the process may seem complex at first, breaking it into smaller steps makes it more manageable and easier to implement in real projects.

With registration, login, token handling, and protected routes in place, there is now a solid foundation for authentication. This setup can be extended with features like password reset, email verification, and role-based access as applications grow. Such structured development approaches are commonly followed by a website design company in Coimbatore, where security, scalability, and clean architecture are important aspects of building reliable web applications.

Top comments (0)