Complete login system with Node.js & Vue.js | RestAPI & JWT | Part [1/2]
Tags: node, javascript, vue, tutorial
Published: 2019-11-16 11:07:32

_Originally published on [webdeasy.de](https://webdeasy.de/en/complete-login-system-with-node-js-vue-js-restapi-jwt-part-1-2/?referer=dev-1fm6)!_

In this article you will learn how to use __Node.js, JWT (JSON Web Tokens)__ and __MySQL__ to create your own __RestAPI__ for user authentication – a complete login system.

_This article is the first part of the two-part series **Complete Login System with Node.js & Vue.js**. We take care of the implementation of a complete login system with Node.js as backend and Vue.js as frontend. The tutorial is divided into two parts, so that you are not bound to a Vue.js frontend, but the restAPI, which we develop in this article, can be applied to other frontends as well as to Angular or React._

➡️ [Part 2: Complete login system with Node.js & Vue.js | Vuex](https://webdeasy.de/en/complete-login-system-with-node-js-vue-js-vuex-part-2-2/?referer=dev-1fm6)

#Our goal for part 1: RestAPI with JWT and MySQL
We create a Node.js application that runs on our local server. We have a [MySQL](https://webdeasy.de/en/category/sql-en/?referer=dev-1fm6) database in which our user data is stored. For authentication we have to query this data and can open a session for the user with the help of the [JWT](https://jwt.io/) extension.

At the end you have an executable application that you can deploy on your own server with the help of [this guide](https://webdeasy.de/en/deploy-node-js-app-with-plesk/?referer=dev-1fm6). But now we finally want to start! 🙂
![Cup with begin label](https://webdeasy.de/wp-content/uploads/2019/09/danielle-macinnes-IuLgi9PWETU-unsplash-e1569668928625-2400x726.jpg)


#1. What is a RestAPI?
A RestAPI represents the interface between server and client. Via normal HTTP requests we reach the server and can execute programmed functions such as authenticating a user with the corresponding password.

Since this tutorial is not suitable for absolute beginners, I assume that you are already a little familiar with Node.js, which is why we skip the installation and come directly to the exciting part. If this is not the case, you will find [here](https://webdeasy.de/en/the-ultimate-node-js-beginner-tutorial/?referer=dev-1fm6) a good guide for getting started with Node.js.


#2. Install dependencies
So our Node.js app is ready to install the dependencies. We need the following modules:
![Alt Text](https://thepracticaldev.s3.amazonaws.com/i/7s79iriir3gcp894ba9y.PNG)

We install these modules using the following CLI command:
```
npm install bcryptjs body-parser express jsonwebtoken mysql uuid cors
```


#3. Set up database
For the database I use [XAMPP](https://www.apachefriends.org/de/index.html), so I can host my own database locally. Of course you can also use any other (remote) database.

For our login system we only need a table according to the following scheme:
![ER model](https://webdeasy.de/wp-content/uploads/2019/09/image.jpg)

In the database, our table then looks like this:
![phpmyadmin database structure](https://webdeasy.de/wp-content/uploads/2019/09/node-jwt-db.png)

So that we can also access this connection via our Node.js application, we create our own class file, which we later include in our router.
```javascript
// lib/db.js
const mysql = require('mysql');
const connection = mysql.createConnection({
  host: 'localhost',
  user: 'node-jwt',
  database: 'node-jwt',
  password: '********'
});
connection.connect();
module.exports = connection;
```

#4. Setting up an Express Router and creating routes
Our entry file is the _index.js_ and contains the starting of our web servers and the integration of the routes we define in the file _routes/router.js_.
```javascript
// index.js
const express = require('express');
const app = express();
const bodyParser = require('body-parser');
const cors = require('cors');
// set up port
const PORT = process.env.PORT || 3000;
app.use(bodyParser.json());
app.use(cors());
// add routes
const router = require('./routes/router.js');
app.use('/api', router);
// run server
app.listen(PORT, () => console.log(`Server running on port ${PORT}`));
```

In the _router.js_ we define our routes and then pack the logic into them. The reason why we use an extra file here is the clarity. If your application has 20 or more routes at some point, the _index.js_ will be chaotic. That’s why we outsource our routes.

```javascript
// routes/router.js
const express = require('express');
const router = express.Router();
const bcrypt = require('bcryptjs');
const uuid = require('uuid');
const jwt = require('jsonwebtoken');
const db = require('../lib/db.js');
const userMiddleware = require('../middleware/users.js');
router.post('/sign-up', (req, res, next) => {});
router.post('/login', (req, res, next) => {});
router.get('/secret-route', (req, res, next) => {
  res.send('This is the secret content. Only logged in users can see that!');
});
module.exports = router;
```


Here we register the route _/api/sign-up_ for registration and _/api/login_ for login. We also have the route _/secret-route_, which you should only be able to call if you are logged in. Currently every user can access it. More about this later.

In line 10 we also include our file for the database connection.

We also include the file _../middleware/users.js_, which contains the code to verify the requests. This means that we check if the user has entered a password and the username complies with the guidelines. We later switch these queries as middleware into the call of our routes.


#5. Creating Middleware (Validation)
A middleware is a small program, which is switched between two components. In this case, between our request and the actual registration, we have a middleware that validates the entered data. For the registration a validation can look like this:
```javascript
// middleware/users.js
module.exports = {
  validateRegister: (req, res, next) => {
    // username min length 3
    if (!req.body.username || req.body.username.length < 3) {
      return res.status(400).send({
        msg: 'Please enter a username with min. 3 chars'
      });
    }
    // password min 6 chars
    if (!req.body.password || req.body.password.length < 6) {
      return res.status(400).send({
        msg: 'Please enter a password with min. 6 chars'
      });
    }
    // password (repeat) does not match
    if (
      !req.body.password_repeat ||
      req.body.password != req.body.password_repeat
    ) {
      return res.status(400).send({
        msg: 'Both passwords must match'
      });
    }
    next();
  }
};
```

When calling our _/sign-up_ route, our middleware should be executed. To do this, change the marked line as follows:
```javascript
// routes/router.js
const express = require('express');
const router = express.Router();
const userMiddleware = require('../middleware/users.js');
router.post('sign-up', userMiddleware.validateRegister, (req, res, next) => {});
router.post('login', (req, res, next) => {});
module.exports = router;
```


#6. Register (/sign-up) route (with JWT)
To add a new user to the database, we have to check if the username does not yet exist. If the user exists, an error message is issued. If the user does not yet exist, our module __bcrypt__ is used to hash (encrypt) the entered password and then enter all data into the database.
```javascript
// routes/router.js
router.post('/sign-up', userMiddleware.validateRegister, (req, res, next) => {
  db.query(
    `SELECT * FROM users WHERE LOWER(username) = LOWER(${db.escape(
      req.body.username
    )});`,
    (err, result) => {
      if (result.length) {
        return res.status(409).send({
          msg: 'This username is already in use!'
        });
      } else {
        // username is available
        bcrypt.hash(req.body.password, 10, (err, hash) => {
          if (err) {
            return res.status(500).send({
              msg: err
            });
          } else {
            // has hashed pw => add to database
            db.query(
              `INSERT INTO users (id, username, password, registered) VALUES ('${uuid.v4()}', ${db.escape(
                req.body.username
              )}, ${db.escape(hash)}, now())`,
              (err, result) => {
                if (err) {
                  throw err;
                  return res.status(400).send({
                    msg: err
                  });
                }
                return res.status(201).send({
                  msg: 'Registered!'
                });
              }
            );
          }
        });
      }
    }
  );
});
```

Important is the function `db.escape()`, e.g. in line 23. This masks passed parameters to avoid SQL injection. If the entry of the user is successful, the status code 201 (“created”) is returned and the function call is terminated.


#7. Login (/login) route (with JWT)
In addition to the registration process, we have a login route to log in for already registered users. Here you can search for the appropriate database entry by user name. Then the entered password from the database is checked with the help of `jwt.compare()`. A short SQL query sets the last login date/time in line 44 to the current value.
```javascript
// routes/router.js
router.post('/login', (req, res, next) => {
  db.query(
    `SELECT * FROM users WHERE username = ${db.escape(req.body.username)};`,
    (err, result) => {
      // user does not exists
      if (err) {
        throw err;
        return res.status(400).send({
          msg: err
        });
      }
      if (!result.length) {
        return res.status(401).send({
          msg: 'Username or password is incorrect!'
        });
      }
      // check password
      bcrypt.compare(
        req.body.password,
        result[0]['password'],
        (bErr, bResult) => {
          // wrong password
          if (bErr) {
            throw bErr;
            return res.status(401).send({
              msg: 'Username or password is incorrect!'
            });
          }
          if (bResult) {
            const token = jwt.sign({
                username: result[0].username,
                userId: result[0].id
              },
              'SECRETKEY', {
                expiresIn: '7d'
              }
            );
            db.query(
              `UPDATE users SET last_login = now() WHERE id = '${result[0].id}'`
            );
            return res.status(200).send({
              msg: 'Logged in!',
              token,
              user: result[0]
            });
          }
          return res.status(401).send({
            msg: 'Username or password is incorrect!'
          });
        }
      );
    }
  );
});
```

In lines 36 and 37 we pass variables that we want to “store” in the JWT token. This gives us access to these variables in the protected routes.

In line 39 you have to pass a key with which the JWT token is generated, this is important for the verification later. Here you can enter any string.

You can also specify in line 40 how long the token should be valid. Values like “1h” or “3m” are valid here. You can also read about the individual values and parameters [in the documentation](https://www.npmjs.com/package/jsonwebtoken).

If the password is wrong or the username does not exist, an error message is displayed. This message is intentionally identical, as a potential attacker could otherwise obtain information about the existence of individual user profiles.

If the login is successful, the user object and the token generated by JWT are returned. This token is important for all routes in which you should be logged in. In part 2 (Vue.js Frontend) you will learn how to pass this token with every request. If you test the RestAPI with [Postman](https://www.getpostman.com/), you can specify the token with the key “Authorization” as value according to the following syntax: “Bearer KEY”.
![Postman Bearer](https://webdeasy.de/wp-content/uploads/2019/09/bearer.png)


#8. Protect routes with login
The most important routes are now ready. We can add new users and log in with existing accounts. Now we want to protect routes. This means that only registered users have access to them.

Therefore we create a new middleware in our _users.js_. The token is taken from the header of the request and verified by JWT.
```javascript
// middleware/users.js
isLoggedIn: (req, res, next) => {
  try {
    const token = req.headers.authorization.split(' ')[1];
    const decoded = jwt.verify(
      token,
      'SECRETKEY'
    );
    req.userData = decoded;
    next();
  } catch (err) {
    return res.status(401).send({
      msg: 'Your session is not valid!'
    });
  }
}
```
In the marked line you have to enter the same key with which you have already generated the JWT.

To protect a route now, simply include this middleware when calling the route as follows:
```javascript
// routes/router.js
router.get('/secret-route', userMiddleware.isLoggedIn, (req, res, next) => {
  console.log(req.userData);
  res.send('This is the secret content. Only logged in users can see that!');
});
```

The `req.userData` contains the data we have stored in the JWT key (in this case `username` and `userId`). This allows us to read user-defined values from the database using the `userId` for protected routes, for example.


#9. Conclusion
➡️ __Continue with part 2: [Complete login system with Node.js & Vue.js | Vuex | Part [2/2]](https://webdeasy.de/en/complete-login-system-with-node-js-vue-js-vuex-part-2-2/?referer=dev-1fm6)__

That?s it! In the first part we have now written a complete RestAPI for validation and session handling for our application. You can use this system for your frontend (no matter if Angular, React or Vue).

_Thanks for reading! If you liked this article, please let me know and share it! If you want to you can check out [my blog](https://webdeasy.de/en/?referer=dev-1fm6) and follow me on [twitter](https://twitter.com/WebDEasy/)!_ 😊