REST API Security with Node, Express, PostgreSQL, Sequelize and Oauth2

REST API Security with Node, Express, PostgreSQL, Sequelize and Oauth2

A comprehensive step by step tutorial on building REST API security using Node.js, Express.js, PostgreSQL, Sequelize, and Oauth2.

A comprehensive step by step tutorial on building REST API security using Node.js, Express.js, PostgreSQL, Sequelize, and Oauth2.

This tutorial divided into several steps:

Step #1: Create Express.js Project and Install Required Modules Step #2: Add Sequelize and Express Oauth Server Modules Step #3: Create or Generate Sequelize Models and Migrations Step #4: Create an Express Controller Step #5: Implementing OAuth2 REST API Endpoint Step #6: Run and Test Secure Node.js, Express.js, PostgreSQL, and Oauth2

Full source code: https://github.com/didinj/node-express-oauth2-postgresql.git


Until now, OAuth2 still very popular in REST API, Web, and Mobile App development for security or authentication. So, we will rewrite the comprehensive tutorial on building REST API security using Node.js, Express.js, PostgreSQL, Sequelize, and Oauth2 using the Express-Oauth-Server module.

In this example, we will show you simple Oauth2 grant types that mostly used in mobile or web applications. They are password and refresh token grant types. So, the Oauth2 endpoint can be '/oauth/token' with differents grants values for password and refresh_token. Also, we will add the additional endpoint for signup and secure API-endpoint.

The following tools, frameworks, and modules are required for this tutorial:

  1. Node.js
  2. PostgreSQL Server
  3. Express.js
  4. Sequelize.js
  5. Express Oauth Server
  6. Terminal or Command Line
  7. Text Editor or IDE
  8. Postman

We assume that you have installed the PostgreSQL server in your machine or can use your own remote server (we are using PostgreSQL 12.3). Also, you have installed Node.js on your machine and can run node, npm or yarn command in your terminal or command line. Next, check their version by type these commands in your terminal or command line.

node -v
v12.18.0
npm -v
6.14.7
yarn -v
1.22.5

That the versions that we are uses. Let's continue with the main steps.

Step #1: Create Express.js Project and Install Required Modules

We will create a new Express.js application for REST API using Express Generator. Open your terminal or node command line the go to your projects folder. First, install express-generator using this command.

sudo npm install -g express-generator

Next, create an Express.js app using this command.

express express-oauth2-postgre --view=ejs

This will create Express.js project with the EJS view instead of the Jade view template because using the '--view=ejs' parameter. Next, go to the newly created project folder then install node modules.

cd express-oauth2-postgre && npm install

You should see the folder structure like this.

.
|-- app.js
|-- bin
|   `-- www
|-- node_modules
|-- package-lock.json
|-- package.json
|-- public
|   |-- images
|   |-- javascripts
|   `-- stylesheets
|       `-- style.css
|-- routes
|   |-- index.js
|   `-- users.js
`-- views
    |-- error.ejs
    `-- index.ejs

There's no view yet using the latest Express generator. We don't need it because we will create a REST API.

Step #2: Add Sequelize and Express Oauth Server Modules

Now, we will install all required modules such as Sequelize, PostgreSQL, Brcypt, Express Oauth Server (Node Oauth2 included), Body Parser, PostgreSQL. Type this command to install all of them.

npm install --save sequelize body-parser pg pg-hstore pg-promise bcrypt-nodejs express-oauth-server

Also, we need Sequelize-CLI to generate config, models, seeders, and migrations. For that, type this command to install Sequelize-CLI globally.

sudo npm install -g sequelize-cli

Next, create a new file at the root of the project folder.

touch .sequelizerc

Open and edit that file using your IDE or Text Editor then add these lines of codes.

const path = require('path');

module.exports = {
  "config": path.resolve('./config', 'config.json'),
  "models-path": path.resolve('./models'),
  "seeders-path": path.resolve('./seeders'),
  "migrations-path": path.resolve('./migrations')
};

That files will tell Sequelize initialization to generate config, models, seeders, and migrations files to specific directories. Next, type this command to initialize the Sequelize.

sequelize init

That command will create config/config.json, models/index.js, migrations, and seeders directories and files. Next, open and edit config/config.json then make it like this.

{
  "development": {
    "username": "djamware",
    "password": "[email protected]@r3",
    "database": "express-oauth2",
    "host": "127.0.0.1",
    "dialect": "postgres"
  },
  "test": {
    "username": "root",
    "password": "[email protected]@r3",
    "database": "express-oauth2",
    "host": "127.0.0.1",
    "dialect": "postgres"
  },
  "production": {
    "username": "root",
    "password": "[email protected]@r3",
    "database": "express-oauth2",
    "host": "127.0.0.1",
    "dialect": "postgres"
  }
}

We use the same configuration for all the environment except the database name. Before running and test the connection, make sure you have created a database as described in the above configuration. You can use the psql command to create a user and database.

psql postgres --u postgres

Next, type this command for creating a new user with a password then give access for creating the database.

postgres-## CREATE ROLE djamware WITH LOGIN PASSWORD '[email protected]@r3';
postgres-## ALTER ROLE djamware CREATEDB;

Quit psql then log in again using the new user that previously created.

postgres-## \q
psql postgres -U djamware

Enter the password, then you will enter this psql console.

psql (12.3)
Type "help" for help.

postgres=>

Type this command to creating a new database.

postgres=> CREATE DATABASE express_oauth2;

Then give that new user privileges to the new database then quit the psql.

postgres=> GRANT ALL PRIVILEGES ON DATABASE express_oauth2 TO djamware;
postgres=> \q

Step #3: Create or Generate Sequelize Models and Migrations

We will use Sequelize-CLI for generating a new model. Type this command to create a model for Products and User model for authentication.

sequelize model:create --name OAuthTokens --attributes accessToken:string,accessTokenExpiresAt:date,refreshToken:string,refreshTokenExpiresAt:date,clientId:integer,userId:integer
sequelize model:create --name OAuthClients --attributes clientId:string,clientSecret:string,redirectUris:string,grants:array
sequelize model:create --name OAuthUsers --attributes username:string,password:string,name:string

That command creates a model file to the model's folder and a migration file to the migrations folder. What we need is associations between models or tables and additional function inside the modules. Next, modify models/oauthusers.js and then import this module.

var bcrypt = require('bcrypt-nodejs');

Add the new methods to the OAuthUsers model that convert the plain password to the encrypted password using Bscrypt, also, association with OAuthTokens. So, the oauthusers.js class will be like this.

'use strict';
const bcrypt = require('bcrypt-nodejs');
const { Model } = require('sequelize');

module.exports = (sequelize, DataTypes) => {
  class OAuthUsers extends Model {
    /**
     * Helper method for defining associations.
     * This method is not a part of Sequelize lifecycle.
     * The `models/index` file will call this method automatically.
     */
    static associate(models) {
      OAuthUsers.hasOne(models.OAuthTokens, {
        foreignKey: 'userId',
        as: 'token',
      });
    }
  };
  OAuthUsers.init({
    username: DataTypes.STRING,
    password: DataTypes.STRING,
    name: DataTypes.STRING
  }, {
    sequelize,
    modelName: 'OAuthUsers',
  });
  OAuthUsers.beforeSave((user) => {
    if (user.changed('password')) {
      user.password = bcrypt.hashSync(user.password, bcrypt.genSaltSync(10), null);
    }
  });
  return OAuthUsers;
};

Next, modify models/oauthtokens.js then add the association to OAuthClients and OAuthUsers. So, the whole OAuthTokens will look like this.

'use strict';
const {
  Model
} = require('sequelize');

module.exports = (sequelize, DataTypes) => {
  class OAuthTokens extends Model {
    /**
     * Helper method for defining associations.
     * This method is not a part of Sequelize lifecycle.
     * The `models/index` file will call this method automatically.
     */
    static associate(models) {
      OAuthTokens.belongsTo(models.OAuthClients, {
        foreignKey: 'clientId',
        as: 'client',
      });
      OAuthTokens.belongsTo(models.OAuthUsers, {
        foreignKey: 'userId',
        as: 'user',
      });
    }
  };
  OAuthTokens.init({
    accessToken: DataTypes.STRING,
    accessTokenExpiresAt: DataTypes.DATE,
    refreshToken: DataTypes.STRING,
    refreshTokenExpiresAt: DataTypes.DATE,
    clientId: DataTypes.INTEGER,
    userId: DataTypes.INTEGER
  }, {
    sequelize,
    modelName: 'OAuthTokens',
  });
  return OAuthTokens;
};

Next, modify models/oauthclients.js then add the association to OAuthTokens. So, the whole OAuthClients will look like this.

'use strict';
const {
  Model
} = require('sequelize');

module.exports = (sequelize, DataTypes) => {
  class OAuthClients extends Model {
    /**
     * Helper method for defining associations.
     * This method is not a part of Sequelize lifecycle.
     * The `models/index` file will call this method automatically.
     */
    static associate(models) {
      OAuthClients.hasOne(models.OAuthTokens, {
        foreignKey: 'clientId',
        as: 'token',
      });
    }
  };
  OAuthClients.init({
    clientId: DataTypes.STRING,
    clientSecret: DataTypes.STRING,
    redirectUris: DataTypes.STRING,
    grants: DataTypes.ARRAY(DataTypes.STRING)
  }, {
    sequelize,
    modelName: 'OAuthClients',
  });
  return OAuthClients;
};

Full article: https://www.djamware.com/post/5f808519b9ebd3190382a52f/rest-api-security-with-node-express-postgresql-oauth2

node express postgresql api security

Bootstrap 5 Complete Course with Examples

Bootstrap 5 Tutorial - Bootstrap 5 Crash Course for Beginners

Nest.JS Tutorial for Beginners

Hello Vue 3: A First Look at Vue 3 and the Composition API

Building a simple Applications with Vue 3

Deno Crash Course: Explore Deno and Create a full REST API with Deno

How to Build a Real-time Chat App with Deno and WebSockets

Convert HTML to Markdown Online

HTML entity encoder decoder Online

Top 10 API Security Threats Every API Team Should Know

Learn what are the most important API security threats engineering leaders should be aware of and steps you can take to prevent them

API Security Weekly: Issue #101

After the special 100th edition last week, which was all about API security advice from the industry’s thought leaders, this week we are back to our regular API security news, and we have twice the number of them, from the past two weeks.

Building REST API using Node, Express, Sequelize and PostgreSQL

Building RESTful API using Node.js, Express.js, Sequelize.js, and PostgreSQL. Learn how to create a little complex table association or relationship with CRUD (Create, Read, Update, Delete) operations. Create Express.js Project and Install Required Modules. Add and Configure Sequelize.js Module and Dependencies. Create or Generate Sequelize Models and Migrations. Create Express Controller and Router for Classroom Model

How to Build and Deploy a Node.js, Express and PostgreSQL REST API

Recently, I wanted to create and host a Node server, and discovered that Heroku is an excellent cloud platform service that has free hobby hosting for Node and PostgreSQL, among many other languages and databases. This tutorial walks through creating a local REST API with Node using an Express server and PostgreSQL database. It also lists the instructions for deploying to Heroku. How to Build and Deploy a Node.js, Express, & PostgreSQL REST API

[Hindi] Express.js Tutorial: Build RESTful APIs with Node and Express - Part 1

Express.js Tutorial: Building RESTful APIs with Node Express. nodejs tutorial with api building with get and post methods.