javascriptexpressjwtbackendreact-fullstack

Error 403 when attempting to register a user - Need assistance resolving the issue


I am currently developing a web application that includes user registration functionality. However, when I try to register a new user, I encounter an "Error 403" response in the console. This error prevents the user from being registered successfully. Front-end:

import React from 'react';
import { useState } from 'react';
import { useNavigate } from 'react-router-dom';

function RegisterAndLogin() {
    const navigate = useNavigate();


    const [email, setEmail] = useState('')
    const [password, setPassword] = useState('')

    async function registerUser(event){
        event.preventDefault();
        const response = await fetch('http://localhost:3000/api/auth/register', {
            method: 'POST',
            headers: {
                'Content-type': 'application/json',
            },
            body: JSON.stringify({
                email,
                password,
            })
        });

        const data = await response.json();
        if (data.status === 201) {
            navigate('/login')
        }
    }

  return (
    <div>
        <h1>REGISTER</h1>
        <form onSubmit={registerUser}>
                <input
                    value={email}
                    onChange={(e) => setEmail(e.target.value)}
                    type="email"
                    placeholder="Email"
                />
                <br />
                <input
                    value={password}
                    onChange={(e) => setPassword(e.target.value)}
                    type="password"
                    placeholder="Password"
                />
                <br />
                <input type="submit" value="Register" />
        </form>
    </div>
  )
}

export default RegisterAndLogin;

Back-end: authController.js file:

const bcrypt = require('bcrypt');
const jwt = require('jsonwebtoken');
const User = require('../models/user');
require('dotenv').config();

exports.registerUser = async (req, res) => {
  try {
    const { email, password } = req.body;

    const existingUser = await User.findOne({ email });
    if (existingUser) {
      return res.status(409).json({ error: 'User already exists!' });
    }

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

    const newUser = await User.create({ email, password: hashPassword });
    

    // Generate JWT token after successful registration
    const token = jwt.sign(
      { userId: newUser._id, email: newUser.email },
      process.env.JWT_SECRET,
      { expiresIn: '2h' }
    );

    newUser.token = token;

    res.status(201).json(newUser);

  } catch (error) {
    console.log(error);
    return res.status(500).json({ error: 'Internal server error!' });

  }
};

exports.loginUser = async (req, res) => {
  try {
    const { email, password } = req.body;

    const user = await User.findOne({ email });
    if (!user) {
      return res.status(401).json({ error: 'Authentication failed!' });
    }

    const validatePassword = await bcrypt.compare(password, user.password);
    if (!validatePassword) {
      return res.status(401).json({ error: 'Password is wrong!' });
    }

    // Generate JWT token after successful login
    const token = jwt.sign(
      { userId: user._id, email: user.email },
      process.env.JWT_SECRET,
      { expiresIn: '2h' }
    );

    user.token = token;


    return res.status(200).json({ token });

  } catch (error) {
    console.log(error);
    return res.status(500).json({ error: 'Internal server error!' });
  }
};

authMiddleware.js file:

const jwt = require('jsonwebtoken');
require('dotenv').config();

exports.authenticateToken = (req, res, next) => {
  const token =
    req.body.token || req.query.token || req.headers["x-access-token"];

  if (!token) {
    return res.status(403).json({ error:"A token is required for authentication"});
  }
  try {
    const decoded = jwt.verify(token, process.env.JWT_SECRET);
    req.user = decoded;
  } catch (err) {
    return res.status(401).json({ error:"Invalid Token"});
  }
  return next();
};

app.js file:

const mongoose = require("mongoose");
const cors = require("cors");
const dotenv = require('dotenv');
const cookieParser = require("cookie-parser")

const authMiddleware = require('./middlewares/authMiddleware');
const authRoutes = require('./routes/routes');
const User = require('./models/user');

const app = express();



dotenv.config();
app.use(express.json());
app.use(cookieParser());
app.use(cors({ origin: 'http://127.0.0.1:5173' }));

const url = process.env.MONGO_URL;
mongoose
  .connect(url, { useNewUrlParser: true, useUnifiedTopology: true })
  .then(() => {
    console.log("Connected to MongoDB database!");
  })
  .catch((error) => {
    console.error("Failed to connect to MongoDB Atlas:", error);
});

app.use(authMiddleware.authenticateToken);

app.use('/api/auth', authRoutes);

app.get('/test', (req,res) => {
    res.json("test ok");
});

app.listen(3000, () => {
    console.log('Server is running on port 3000');
});

Please help me resolve this issue.

Expected Result: The user should be successfully registered, and I should receive a success response or be redirected to a new page.

Actual Result: Upon submitting the registration form, the browser console displays an "Error 403" message, and the user registration fails.


Solution

  • You seem to have protected your registration route. Usually, you want to leave your login and register routes unprotected, since you don't want users to have to be logged in to be able to login (or register).

    Try registering your auth routes within express before registering your authenticateToken route so auth routes will match before going into the token validation middleware
    swap the app.use(authMiddleware.authenticateToken); line
    and
    app.use('/api/auth', authRoutes);

    Middleware functions are executed sequentially, therefore the order of middleware inclusion is important.

    From the express docs