Login / Register authentication
Tags: javascript, webdev, beginners
Published: 2022-08-03 13:52:45

### Overview
This is a simple login authentication for backend. You need to basic understanding on how to use Express.js, Mongoose, and Node.js. I assumed that you already have an app that is connected to MongoDB so I won't explain on that and just focus on the login and register part.

You need to install the following libraries:

```
yarn add express jsonwebtoken bcrypt
```

### Technologies
In high level explanation:
1. express.js - backend web application framework for Node.js
2. jsonwebtoken - standard way of transmitting information between parties as a JSON object.
3. bcrypt - is a password-hashing function.

### The code
#### Register

Let's say we are registering a google account. There are rules that we need to follow, those rules should be met in order to successfully create and account. Here we call them error handling.

Let's check if the request is in proper type and length:
```
const {username, password, email} = req.body;
  if (!username || typeof username !== "string"){
    return res.json({status: 'error', error: 'Invalid username'})
  }
  if (!password || typeof password !== "string"){
    return res.json({status: 'error', error: 'Invalid password'})
  }
  if (password.length < 6){
    return res.json({status: 'error', error: 'Password too short. Should atleast be 6 characters'})
  }
  if (!email || typeof password !== "string"){
    return res.json({status: 'error', error: 'Invalid Email'})
  }
```

Then check if it is unique:
User is the name of the mongoDB model.

```
const newUser = await User.findOne({username}).lean()
const newMail = await User.findOne({email}).lean()
if(newUser){
    return res.status(500).json({status: 'error', error: 'Username is already inuse'})
  }
  if(newMail){
    return res.status(500).json({status: 'error', error: 'Email is already inuse'})
  }
```

After that we hash the password to be unreadable in the database:

```
const user = new User({
    username: username,
    password: await bcrypt.hash(password, 10),
    email: email
  })
```

Then try to save the account in the database:

```
try {
    const saveUser = await user.save()
    res.status(200).json({status:'ok', message: 'Account succesfully made'})
  }
  catch(err){
    return res.status(400).json({msg: err.message})
  }
```
When you've register an account you will notice that the password is different from what you've typed. 


#### Login
You need first to create a secret token, it is like your housekey, use to prevent others from accessing your important things while making you able to access it.

```
JWT_SECRET = I'm am the key~~@-@~~E.
```

Hashing is a one-way operation which means the server cannot decrypt the password. What you can do is to compare the hashed typed(password) and server password(user.password) to verify.

```
bcrypt.compare(password, user.password)
```

jwt.sign is used to create a token that usually is stored in the localstorage to access the data.

```
const token = jwt.sign({ id: user._id, username: user.username}, JWT_SECRET)
```

### Login Fullcode
```
const {username, password} = req.body;
JWT_SECRET = I'm am the key~~@-@~~E.

  // check username, password, email exist
  if (!username || typeof username !== "string"){
    return res.json({status: 'error', error: 'Invalid username'})
  }
  if (!password || typeof password !== "string"){
    return res.json({status: 'error', error: 'Invalid password'})
  }
  if (password.length < 6){
    return res.json({status: 'error', error: 'Password too short. Should atleast be 6 characters'})
  }
  
  try {
    const user = await User.findOne({username}).lean()  
    if(!user){
      return res.status(500).json({status: 'error', error: 'Invalid username or password'})
    }
    if(await bcrypt.compare(password, user.password)){
      const token = jwt.sign({ id: user._id, username: user.username}, JWT_SECRET)
      return res.status(200).header('auth-token', token).send({token, status: 'ok'})
    }
    return res.status(500).json({status: 'error', error: 'Invalid username or password'})
  }
  catch(err){
    return res.status(500).json({msg: err.message})
  }
```

### Register Fullcode
```
const {username, password, email} = req.body;
  if (!username || typeof username !== "string"){
    return res.json({status: 'error', error: 'Invalid username'})
  }
  if (!password || typeof password !== "string"){
    return res.json({status: 'error', error: 'Invalid password'})
  }
  if (password.length < 6){
    return res.json({status: 'error', error: 'Password too short. Should atleast be 6 characters'})
  }
  if (!email || typeof password !== "string"){
    return res.json({status: 'error', error: 'Invalid Email'})
  }
  const newUser = await User.findOne({username}).lean()
  const newMail = await User.findOne({email}).lean()
  if(newUser){
    return res.status(500).json({status: 'error', error: 'Username is already inuse'})
  }
  if(newMail){
    return res.status(500).json({status: 'error', error: 'Email is already inuse'})
  }
  const user = new User({
    username: username,
    password: await bcrypt.hash(password, 10),
    email: email
  })
  try {
    const saveUser = await user.save();
    //res.send({user: user._id})
    res.status(200).json({status:'ok', message: 'Account succesfully made'})
  }
  catch(err){
    return res.status(400).json({msg: err.message})
  }
```