How to Implement CORS and Authentication in NodeJS
Tags: node, javascript, webdev, beginners
Published: 2022-01-08 23:26:12

In this tutorial, we will learn how to authenticate users, secure endpoints and Cross-Origin Resource Sharing (CORS) in NodeJs.

### Prerequisites

You'll need the following to follow along with this tutorial: 
- A working grasp of JavaScript.
- A good understanding of Node.js.
- A working knowledge of MongoDB or another database of your choice.
- [Postman](https://www.postman.com/) and a basic understanding of how to utilize it.


## What is authentication and authorization

Security uses authentication and authorization, especially when gaining access to a system. But there's a big difference between getting into a house (authentication) and what you can do once you're there (authorization).

## Authentication

Authentication is the process of confirming a user's identity by obtaining credentials and utilizing those credentials to validate the user's identity. If the certificates are valid, the authorization procedure begins.

You were already familiar with the authentication procedure because we all go through it daily, whether at work (logging onto your computer) or at home (passwords) (logging into a website). However, most "things" connected to the Internet require you to provide credentials to prove your identity.

## Authorization

The process of granting authenticated users access to resources by verifying whether they have system access permissions is known as authorization. In addition, authorization allows you to restrict access privileges by granting or denying specific licenses to authenticated users.

After the system authenticates your identity, authorization occurs, providing you full access to resources such as information, files, databases, finances, locations, and anything else. On the other hand, approval impacts your ability to access the system and the extent to which you can do so.

## Cross-Origin Resource Sharing (CORS)

[CORS](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS) is an HTTP header-based system that allows a server to specify any other origins (domain, scheme, or port) from which a browser should enable resources to be loaded other than its own. CORS also uses a system in which browsers send a "preflight" request to the server hosting the cross-origin help to ensure that it will allow the actual request.

> We will be using JSON web token standard for representing claims between two parties

### What is JWT

JSON Web Tokens (JWT) are an open industry standard defined by RFC 7519 to represent claims between two parties. You can use [jwt.io](https://jwt.io) to decode, verify, and create JWT, for example.

JWT defines a concise and self-contained way for exchanging information between two parties as a JSON object. This information may be reviewed and trusted because it is signed. JWTs can be signed with a secret (using the HMAC algorithm) or a public/private key pair from RSA or ECDSA. We'll see some examples of how to use them in a bit.

Let's get started

## Node.js development using a token for authentication

To get started, we'll need to set up our project.

Please navigate to a directory of your choice on your machine and open it in the terminal to launch Visual Studio Code.

Then execute:

```bash
code.
```

> **Note**: If you don't have Visual Studio Code installed on your computer, `code .`  won't work. 


### A - Create a directory and set it up `npm`

Create a directory and initialize `npm` by typing the following command:

- Windows power shell

```bash
mkdir cors-auth-project

cd cors-auth-project

npm init -y
```

- Linux

```bash
mkdir cors-auth-project

cd cors-auth-project

npm init -y
```

### B - Create files and directories

In step A, we initialized npm with the command `npm init -y`, which automatically created a package.json.

We will create the `model`, `middleware`, `config` directory and their files, for example, `user.js`, `auth.js`, `database.js` using the commands below.

```bash
mkdir model middleware config

touch config/database.js middleware/auth.js model/user.js
```

We can now create the `index.js` and `app.js` files in the root directory of our project with the command.

```bash
touch app.js index.js
```

As seen in the illustration below:

![folder structure](https://www.freecodecamp.org/news/content/images/2021/06/Screenshot-2021-06-26-at-19.43.15.png)


### C - Install dependencies

We'll install several dependencies like `mongoose`, `jsonwebtoken`, `express` `dotenv` `bcryptjs` `cors` and development dependency like `nodemon` to restart the server as we make changes automatically.

Because I'll be utilizing MongoDB in this lesson, we'll install mongoose, and the user credentials will be checked against what we have in our database. As a result, the entire authentication process isn't limited to the database we'll use in this tutorial.

```bash
npm install  cors mongoose express jsonwebtoken dotenv bcryptjs 

npm install nodemon -D
```

### D - Create a Node.js server and connect your database

Now, add the following snippets to your `app.js`, `index.js`, `database.js`, and `.env` files in that order to establish our Node.js server and connect our database.

In our `database.js.`

`config/database.js`:
```javascript
const mongoose = require("mongoose");

const { MONGO_URI } = process.env;

exports.connect = () => {
  // Connecting to the database
  mongoose
    .connect(MONGO_URI, {
      useNewUrlParser: true,
      useUnifiedTopology: true,
      useCreateIndex: true,
      useFindAndModify: false,
    })
    .then(() => {
      console.log("Successfully connected to database");
    })
    .catch((error) => {
      console.log("database connection failed. exiting now...");
      console.error(error);
      process.exit(1);
    });
};
```

In our `app.js`:

`auth-cors-project/app.js`
```javascript
require("dotenv").config();
require("./config/database").connect();
const express = require("express");

const app = express();

app.use(express.json());

// Logic goes here

module.exports = app;
```

In our `index.js`:

`auth-cors-project/index.js`
```javascript
const http = require("http");
const app = require("./app");
const server = http.createServer(app);

const { API_PORT } = process.env;
const port = process.env.PORT || API_PORT;

// server listening 
server.listen(port, () => {
  console.log(`Server running on port ${port}`);
});
```

Our file, as you can see, requires various environment variables. If you haven't already, create a new `.env` file and add your variables before running our application.

In our `.env.`

```javascript
API_PORT=4001

MONGO_URI= // Your database URI
```

Edit the scripts object in our `package.json` to look like the one below to start our server.

```javascript
"scripts": {
    "start": "node index.js",
    "dev": "nodemon index.js",
    "test": "echo \"Error: no test specified\" && exit 1"
  }
```

The above snippet was successfully inserted into the` app.js`, `index.js`, and `database.js` files. So, we started by creating our node.js server in `index.js` and then importing the `app.js` file, which already had routes configured.

Then, as mentioned in database.js, we used mongoose to build a database connection.

`npm run dev` is the command to start our application.

Both the server and the database should be up and running without crashing.

### E - Create user model and route

After registering for the first time, we'll establish our schema for the user details, and when logging in, we'll check them against the remembered credentials.

In the model folder, add the following snippet to `user.js`.

`model/user.js`

```javascript
const mongoose = require("mongoose");

const userSchema = new mongoose.Schema({
  first_name: { type: String, default: null },
  last_name: { type: String, default: null },
  email: { type: String, unique: true },
  password: { type: String },
});

module.exports = mongoose.model("user", userSchema);
```

Let's create the routes for `register` and `login`, respectively.

In `app.js` in the root directory, add the following snippet for the registration and login.

`app.js`
```javascript
// importing user context
const User = require("./model/user");

// Register
app.post("/register", (req, res) => {
// our register logic goes here...
});

// Login
app.post("/login", (req, res) => {
// our login logic goes here
});
```

### F - Implement register and login functionality

These two routes will be implemented in our application. Before storing the credentials in our database, we'll use JWT to sign and `bycrypt` to encrypt.

We will: - Get user input from the `/register` route.
- Verify the user's input.
- Check to see if the user has already been created.
- Protect the user's password by encrypting it.
- Make a user account in our database.
- Finally, construct a JWT token that is signed.

Modify the `/register` route structure we created earlier, as shown below.

`app.js`
```javascript
// ...

app.post("/register", async (req, res) => {

  // Our register logic starts here
   try {
    // Get user input
    const { firstName, lastName, email, password } = req.body;

    // Validate user input
    if (!(email && password && firstName && lastName)) {
      res.status(400).send("All input is required");
    }

    // check if user already exist
    // Validate if user exist in our database
    const oldUser = await User.findOne({ email });

    if (oldUser) {
      return res.status(409).send("User Already Exist. Please Login");
    }

    //Encrypt user password
    encryptedUserPassword = await bcrypt.hash(password, 10);

    // Create user in our database
    const user = await User.create({
      first_name: firstName,
      last_name: lastName,
      email: email.toLowerCase(), // sanitize
      password: encryptedUserPassword,
    });

    // Create token
    const token = jwt.sign(
      { user_id: user._id, email },
      process.env.TOKEN_KEY,
      {
        expiresIn: "5h",
      }
    );
    // save user token
    user.token = token;

    // return new user
    res.status(201).json(user);
  } catch (err) {
    console.log(err);
  }
  // Our register logic ends here
});

// ...
```

> **Note:** Update your `.env` file with a `TOKEN_KEY`, which can be a random string.

Using Postman to test the endpoint, we'll get the below response after a successful registration.

![user registration](https://www.freecodecamp.org/news/content/images/2021/06/Screenshot-2021-06-26-at-22.57.16.png)

We will: - Get user input for the `/login` route.
- Verify the user's input.
- Check to see if the user is genuine.
- Compare the user password to the one we saved earlier in our database.
- Finally, construct a JWT token that is signed.

Make the `/login` route structure that we defined earlier look like this.

```javascript
// ...

app.post("/login", async (req, res) => {

  // Our login logic starts here
   try {
    // Get user input
    const { email, password } = req.body;

    // Validate user input
    if (!(email && password)) {
      res.status(400).send("All input is required");
    }
    // Validate if user exist in our database
    const user = await User.findOne({ email });

    if (user && (await bcrypt.compare(password, user.password))) {
      // Create token
      const token = jwt.sign(
        { user_id: user._id, email },
        process.env.TOKEN_KEY,
        {
          expiresIn: "5h",
        }
      );

      // save user token
      user.token = token;

      // user
      return res.status(200).json(user);
    }
    return res.status(400).send("Invalid Credentials");
    
  // Our login logic ends here
});

// ...
```

Using Postman to test, we'll get the response shown below after a successful login.

![user login](https://www.freecodecamp.org/news/content/images/2021/06/Screenshot-2021-06-26-at-23.00.45.png)

### G - Create middleware for authentication

A user can be created and logged in successfully. Despite this, we'll establish a route that requires a user token in the header, which will be the JWT token we created before.

Add the following snippet inside `auth.js`.

`middleware/auth.js`
```javascript
const jwt = require("jsonwebtoken");

const config = process.env;

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

  if (!token) {
    return res.status(403).send("A token is required for authentication");
  }
  try {
    const decoded = jwt.verify(token, config.TOKEN_KEY);
    req.user = decoded;
  } catch (err) {
    return res.status(401).send("Invalid Token");
  }
  return next();
};

module.exports = verifyToken;
```

Create the `/welcome` route and edit app.js with the following code to test the middleware.

`app.js`
```javascript
const auth = require("./middleware/auth");

app.post("/welcome", auth, (req, res) => {
  res.status(200).send("Welcome to FreeCodeCamp 🙌");
});
```

When we try to access the /welcome route we just built without sending a token in the header with the x-access-token key, we get the following response.

![failed response](https://www.freecodecamp.org/news/content/images/2021/06/Screenshot-2021-06-26-at-23.09.13.png)

We can now re-test by adding a token in the header with the key x-access-token.

The response is seen in the image below.

![success response](https://www.freecodecamp.org/news/content/images/2021/06/success-response.png)

## Implementing Cross-Origin Resource Sharing (CORS)

[CORS](https://www.npmjs.com/package/cors) is a node.js package that provides a Connect/Express middleware that can be used to enable CORS with a variety of parameters.

1. Easy to Use (Enable All CORS Requests)

Adding the following snippet to `app.js` allows us to add cors to our application and enable all CORS requests.

```
// ...

const cors = require("cors") //Newly added
const app = express();

app.use(cors()) // Newly added


app.use(express.json({ limit: "50mb" }));

// ...
```

2. Enable CORS for a Single Route

Using the `/welcome` route as an example, We may activate CORS for a single route in our application by adding the following snippet in `app.js.`

```
app.get('/welcome', cors(), auth, (req, res) => {
  res.status(200).send("Welcome to FreeCodeCamp 🙌 ");
});
```

3. Configuring CORS

As shown below, we can set options in the cors package by adding parameters to configure it.

```
// ...

const corsOptions = {
  origin: 'http://example.com',
  optionsSuccessStatus: 200 // for some legacy browsers
}

app.get('/welcome', cors(corsOptions), auth, (req, res) => {
  res.status(200).send("Welcome to FreeCodeCamp 🙌 ");
});

// ...
```

Kindly check out [NPM CORS PACKAGE](https://www.npmjs.com/package/cors) to read more about Cross-Origin Resource Sharing.

You can [click here](https://github.com/Olanetsoft/auth-cors-demo) to check the complete code on GitHub.

## Conclusion
In this article, we learned about JWT, authentication, authorization, and CORS and how to create an API in Node.js that uses a JWT token for authentication.

Thank you!


I'd love to connect with you at [Twitter](https://twitter.com/olanetsoft) | [LinkedIn](https://www.linkedin.com/in/olubisi-idris-ayinde-05727b17a/) | [GitHub](https://github.com/Olanetsoft) | [Portfolio](https://idrisolubisi.com/)

See you in my next blog article. Take care!!!