ubuntu7788
ubuntu7788

Reputation: 115

Getting error while logging in 402 (Payment Required)

I don't understand it. I am not able to login. User is already in my database, and when I log in, it simply says:

POST http://localhost:3000/api/v1/users/login 402 (Payment Required)

When I register for the first time, and then login, login is successful. If I logout, and then try to log in with that same email and password, it's throwing me the above error. I'm not even using someone's API. It's my own created one. It's sending me a response of "incorrect password"

Here's the controller:

loginUser: (req, res, next) => {
    const { email, password } = req.body

    if (!email || !password) {
        return res.status(400).json({ message: "Email and password are must" })
    }

    User.findOne({ email }, (err, user) => {
        if (err) {
            return next(err)
        } else if (!validator.isEmail(email)) {
            return res.status(400).json({ message: "Invalid email" })
        } else if (!user) {
            return res.status(402).json({ error: "User not found" })
        } else if (!user.confirmPassword(password)) {
            return res.status(402).json({ error: "incorrect password" })
        } 
    })
}

User model

const mongoose = require("mongoose")
const bcrypt = require("bcrypt")
const Schema = mongoose.Schema

const userSchema = new Schema({
    username: { type: String, required: true },
    email: { type: String, reuired: true },
    password: { type: String, required: true },
    posts:[{ type: Schema.Types.ObjectId, ref: "Post" }]
}, { timestamps: true })


userSchema.pre("save", function (next) {
    if (this.password) {
        const salt = bcrypt.genSaltSync(10)
        this.password = bcrypt.hashSync(this.password, salt)
    }
    next()
})

userSchema.methods.confirmPassword = function (password) {
    return bcrypt.compareSync(password, this.password)
}

const User = mongoose.model("User", userSchema)

module.exports = User

registration controller

    registerUser: (req, res) => {
        const { username, email, password } = req.body
        User.create(req.body, (err, createdUser) => {
            if (err) {
                return res.status(500).json({ error: "Server error occurred" })
            } else if (!username || !email || !password) {
                return res.status(400).json({ message: "Username, email and password are must" })
            } else if (!validator.isEmail(email)) {
                return res.status(400).json({ message: "Invaid email" })
            } else if (password.length < 6) {
                return res.status(400).json({ message: "Password should be of at least 6 characters" })
            }
            else {
                return res.status(200).json({ user: createdUser })
            }
        })
    }

Edit

loginUser: async (req, res, next) => {
    const { email, password } = req.body

    if (!email || !password) {
        return res.status(400).json({ message: "Email and password are must" })
    }

    await User.findOne({ email }, (err, user) => {
        if (err) {
            return next(err)
        } else if (!validator.isEmail(email)) { 
            return res.status(400).json({ message: "Invalid email" })
        } else if (!user) {
            return res.status(402).json({ error: "User not found" })
        } else if (!user.confirmPassword(password)) {
            return res.status(402).json({ error: "incorrect password" })
        } 
    })
}

new post controller

    newPost: (req, res) => {

    const data = {
      title: req.body.title,
      content: req.body.content,
      user: req.user.userId
    }

    Post.create(data, (err, newPost) => {
      if (err) {
        return res.status(500).json({ error: err })
      } else if (!newPost) {
        return res.status(400).json({ message: "No Post found" })
      } else if (newPost) {
        User.findById(req.user.userId, (err, user) => {
          user.posts.push(newPost._id) //pushing posts documnet objectid to the post array of the user document
          user
            .save()
            .then(() => {
              return res.json(200).json({ user })
            })
            .catch(err => {
              return res.status(500).json({ error: err })
            })
        })
      }
    })
  }

Upvotes: 2

Views: 4569

Answers (1)

Matt Croak
Matt Croak

Reputation: 2888

You might want to refactor your code so that you do the bcrypt operations in controller not in the model. You are checking this.password after the user is updated (creating new posts) and since this is the user, the below code is being met each time you update the user object.

if (this.password) {
        const salt = bcrypt.genSaltSync(10)
        this.password = bcrypt.hashSync(this.password, salt)
}

So your hashing it every time you update the user (create a post). Instead, remove the above code from the userSchema.pre(...) and try doing the bcrypt hashing only when the user first registers.


registerUser: (req, res) => {
        var { username, email, password } = req.body
        if (password) {
           const salt = bcrypt.genSaltSync(10)
           password = bcrypt.hashSync(password, salt)
        }
        User.create(req.body, (err, createdUser) => {
            if (err) {
                return res.status(500).json({ error: "Server error occurred" })
            } else if (!username || !email || !password) {
                return res.status(400).json({ message: "Username, email and password are must" })
            } else if (!validator.isEmail(email)) {
                return res.status(400).json({ message: "Invaid email" })
            } else if (password.length < 6) {
                return res.status(400).json({ message: "Password should be of at least 6 characters" })
            }
            else {
                return res.status(200).json({ user: createdUser })
            }
        })
    }

This way the hashing occurs only once at the creation of the user and should remain consistent throughout other operations.

As for the Can't set headers after they are sent error, you might be sending a response twice, since the error appears to come from the posts controller. You are likely sending the user response and the post response. Maybe don't send the posts response since you will be sending it along in the user response.

More info on the error here.

Upvotes: 1

Related Questions