• Home
  • Blog
  • Creating a secure Node.js-based application with REST services

Creating a secure Node.js-based application with REST services

How to create Secure Node.js-based application with REST services

In today’s digital landscape, security is paramount. Whether you’re developing a new project or enhancing an existing one, ensuring your web application is secure from the ground up is essential. In this guide, we’ll walk you through the process of quickly creating a secure Node.js-based web application with REST APIs.

You’ll learn how to set up Express.js for your backend, implement robust JWT authentication, and use bcrypt for password hashing to protect user data. We’ll also cover how to document your APIs effectively using Swagger and deploy your application on popular cloud platforms like AWS, Google Cloud, or Azure.

By the end of this blog, you’ll have a solid foundation for building a secure and scalable web application, armed with best practices in web development and API security. Let’s dive in and start building!

Set Up Your Development Environment

Make sure you have Node.js and npm installed. You can install them from Node.js official site.

Initialize Your Project

Create a new Node.js project and install necessary packages:

mkdir my-nodejs-app
cd my-nodejs-app
npm init -y
npm install express swagger-ui-express swagger-jsdoc jsonwebtoken bcryptjs cors

Set Up Express Server

Create an index.js file to set up your Express server:

const express = require('express');
const swaggerUi = require('swagger-ui-express');
const swaggerJsdoc = require('swagger-jsdoc');
const jwt = require('jsonwebtoken');
const bcrypt = require('bcryptjs');
const cors = require('cors');

const app = express();
app.use(express.json());
app.use(cors());

const swaggerOptions = {
  swaggerDefinition: {
    openapi: '3.0.0',
    info: {
      title: 'Node.js API',
      version: '1.0.0',
      description: 'A simple Express API'
    },
    servers: [
      {
        url: 'http://localhost:3000'
      }
    ]
  },
  apis: ['./routes/*.js']
};

const swaggerDocs = swaggerJsdoc(swaggerOptions);
app.use('/api-docs', swaggerUi.serve, swaggerUi.setup(swaggerDocs));

// Placeholder for authentication middleware and routes

app.listen(3000, () => {
  console.log('Server is running on http://localhost:3000');
});

Define Routes and Controllers

Create a routes folder and inside it, create a user.js file for user routes:

const express = require('express');
const router = express.Router();
const bcrypt = require('bcryptjs');
const jwt = require('jsonwebtoken');

// Dummy user data
const users = [];

router.post('/register', async (req, res) => {
  const { username, password } = req.body;
  const hashedPassword = await bcrypt.hash(password, 10);
  users.push({ username, password: hashedPassword });
  res.status(201).send('User registered');
});

router.post('/login', async (req, res) => {
  const { username, password } = req.body;
  const user = users.find(u => u.username === username);
  if (!user) {
    return res.status(400).send('User not found');
  }
  const isMatch = await bcrypt.compare(password, user.password);
  if (!isMatch) {
    return res.status(400).send('Invalid credentials');
  }
  const token = jwt.sign({ username: user.username }, 'your_jwt_secret');
  res.json({ token });
});

module.exports = router;

Update index.js to include user routes:

const userRoutes = require('./routes/user');
app.use('/api/users', userRoutes);

Document Your API with Swagger

Add comments to your routes for Swagger documentation. Update user.js:

/**
 * @swagger
 * components:
 *   schemas:
 *     User:
 *       type: object
 *       required:
 *         - username
 *         - password
 *       properties:
 *         username:
 *           type: string
 *           description: The user's username.
 *         password:
 *           type: string
 *           description: The user's password.
 */

/**
 * @swagger
 * /api/users/register:
 *   post:
 *     summary: Register a new user
 *     tags: [User]
 *     requestBody:
 *       required: true
 *       content:
 *         application/json:
 *           schema:
 *             $ref: '#/components/schemas/User'
 *     responses:
 *       201:
 *         description: The user was successfully created
 *       500:
 *         description: Some server error
 */
router.post('/register', async (req, res) => {
  const { username, password } = req.body;
  const hashedPassword = await bcrypt.hash(password, 10);
  users.push({ username, password: hashedPassword });
  res.status(201).send('User registered');
});

/**
 * @swagger
 * /api/users/login:
 *   post:
 *     summary: Log in a user
 *     tags: [User]
 *     requestBody:
 *       required: true
 *       content:
 *         application/json:
 *           schema:
 *             $ref: '#/components/schemas/User'
 *     responses:
 *       200:
 *         description: User logged in successfully
 *       400:
 *         description: Invalid credentials
 */
router.post('/login', async (req, res) => {
  const { username, password } = req.body;
  const user = users.find(u => u.username === username);
  if (!user) {
    return res.status(400).send('User not found');
  }
  const isMatch = await bcrypt.compare(password, user.password);
  if (!isMatch) {
    return res.status(400).send('Invalid credentials');
  }
  const token = jwt.sign({ username: user.username }, 'your_jwt_secret');
  res.json({ token });
});

Secure Communication

Use HTTPS for secure communication. In a development environment, you can use tools like mkcert to create locally trusted development certificates.

Deploy on a Secure Cloud Platform

Deploy your application on a cloud platform like AWS, Google Cloud, or Azure. Use managed services for databases and other infrastructure components. Ensure you enable security features like firewalls, DDoS protection, and automated security updates.

Set Up CI/CD Pipeline

Use GitHub Actions to set up a CI/CD pipeline. Example .github/workflows/node.js.yml:

name: Node.js CI

on:
  push:
    branches: [main]
  pull_request:
    branches: [main]

jobs:
  build:

    runs-on: ubuntu-latest

    strategy:
      matrix:
        node-version: [14, 16]

    steps:
    - uses: actions/checkout@v2
    - name: Use Node.js ${{ matrix.node-version }}
      uses: actions/setup-node@v2
      with:
        node-version: ${{ matrix.node-version }}
    - run: npm install
    - run: npm test
    - run: npm run build

Leave a Comment

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.