DEV Community

Cover image for Authentication and Authorization Microservice with Node.js, Express, PostgreSQL, and 2-Factor : Part 1
Saurabh Sharma
Saurabh Sharma

Posted on

Authentication and Authorization Microservice with Node.js, Express, PostgreSQL, and 2-Factor : Part 1

In today’s digital landscape, securing user authentication is more critical than ever. Whether you're developing a SaaS platform, an enterprise application, or a multi-tenant system, a robust authentication and authorization microservice can help centralize user management and enforce security best practices. In this blog post, we will walk through the complete development of an authentication and authorization microservice using Node.js, Express, and PostgreSQL, incorporating JWT-based authentication, role-based access control (RBAC), and Two-Factor Authentication (2FA) using TOTP (Time-Based One-Time Passwords). We will also ensure industry-grade security practices, including password hashing, input validation, and secure token management. By the end of this guide, you'll have a production-ready microservice that can be integrated with multiple applications, serving as a reliable identity provider. Let’s get started! 🚀

It is part of series:

  • Part 1

  • Part 2

  • Part 3

Authentication & Authorization:

Mechanisms: Username/password, TOTP.

Services: User registration, authenticator registration, login, token issuance (JWT or OAuth2), and role-based access control.

Super Admin: One dedicated user with elevated privileges.

Deployment:

Containerization: Docker support for easier deployment and orchestration (e.g., Kubernetes).

Security:
Industry best practices, such as secure password storage
Initialize Project

Let's start

1. Create directory & initiate npm

mkdir auth-service
cd auth-service
npm init -y
Enter fullscreen mode Exit fullscreen mode
Install typescript and other development dependency
npm install typescript ts-node @types/node --save-dev
tsc --init
Enter fullscreen mode Exit fullscreen mode
Install express framework and database ORM (TypeORM) & pg
npm install express typeorm pg dotenv
npm install @types/express --save-dev
Enter fullscreen mode Exit fullscreen mode
To get it work, open tsconfig.json and add following settings in compilerOptions
"experimentalDecorators": true,
"emitDecoratorMetadata": true,
"strictPropertyInitialization": false,
Enter fullscreen mode Exit fullscreen mode

2. Install Postgres & pgAdmin using docker-compose

create file docker-compose.yml in root and copy the following content

version: "3.8"
services:
  db:
    image: postgres
    container_name: local_pgdb
    restart: always
    ports:
      - "5432:5432"
    environment:
      - POSTGRES_USER=${DB_USER}
      - POSTGRES_PASSWORD=${DB_PASSWORD}
    volumes:
      - local_pgdata:/var/lib/postgresql/data
  pgadmin:
    image: dpage/pgadmin4
    container_name: pgadmin4_container
    restart: always
    ports:
      - "8888:80"
    environment:
      - PGADMIN_DEFAULT_EMAIL=${PGADMIN_DEFAULT_EMAIL}
      - PGADMIN_DEFAULT_PASSWORD=${PGADMIN_DEFAULT_PASSWORD}
    volumes:
      - pgadmin-data:/var/lib/pgadmin

volumes:
  local_pgdata:
  pgadmin-data:
Enter fullscreen mode Exit fullscreen mode

Create .env file in root with your credentials (Don't use the given details)

DB_HOST=localhost
DB_PORT=5432

DB_USERNAME=postgres
DB_PASSWORD=postgres

PGADMIN_DEFAULT_EMAIL=pgadmin@postgres.com
PGADMIN_DEFAULT_PASSWORD=pgadmin
Enter fullscreen mode Exit fullscreen mode
Run the docker
docker-compose up -d
Enter fullscreen mode Exit fullscreen mode
Check the containers status
docker ps
Enter fullscreen mode Exit fullscreen mode

docker ps output

  • you can access the pgAdmin using url http://localhost:8888 
  • login using your credentials and create server connection 
  • host will be container name(eg.local_pgdb) of Postgres container

3. ORM Configuration

create data-source.ts file in src folder with following code

import { DataSource } from "typeorm";
import * as dotenv from 'dotenv';
dotenv.config();

export const AppDataSource = new DataSource({
  type: "postgres", 
  host: "localhost",
  port: 5432,
  username: process.env.DB_USERNAME || "postgres",
  password: process.env.DB_PASSWORD || "postgres",
  database: process.env.DB_DATABASE || "postgres",
  synchronize: true,    // make false for production
  logging: false,
  entities: ["src/entity/**/*.ts"],
  migrations: ["src/migration/**/*.ts"],
  subscribers: ["src/subscriber/**/*.ts"],
});

AppDataSource.initialize()
    .then(() => {
    console.log("Data Source has been initialized!");
  })
  .catch((err) => {
    console.error("Error during Data Source initialization:", err);
  });
Enter fullscreen mode Exit fullscreen mode
Create following folder structure in src folder
  • src/entity
  • src/migration
  • src/subscriber

3.1 Create Database Schema

Create a Userentity in src/entity/User.ts:
import { Entity, PrimaryGeneratedColumn, Column, CreateDateColumn } from 'typeorm';

@Entity()
export class User {
  @PrimaryGeneratedColumn('uuid')
  id: string;

  @Column({ unique: true })
  username: string;

  @Column()
  passwordHash: string;

  @Column({ default: 'user' })
  role: string;

  @Column({ nullable: true })
  totpSecret: string;

  @CreateDateColumn()
  createdAt: Date;
}
Enter fullscreen mode Exit fullscreen mode
Create migration file CreateUserTable in src/migration
npx typeorm-ts-node-commonjs -d ./src/data-source.ts migration:generate ./src/migration/CreateUserTable
Enter fullscreen mode Exit fullscreen mode
Run the migration using following command
npx typeorm-ts-node-commonjs -d src/data-source.ts migration:run
Enter fullscreen mode Exit fullscreen mode

Install other libraries

npm install bcrypt speakeasy qrcode jsonwebtoken express-validator
npm install @types/bcrypt @types/speakeasy  @types/qrcode @types/jsonwebtoken
Enter fullscreen mode Exit fullscreen mode

4. Startup file

Create index.ts file in src folder with following initial code:

import express from 'express';
import { AppDataSource } from './data-source';

const app = express();

app.get('/health', (req, res) => {
  res.send('Auth Microservice is running');
});

AppDataSource.initialize()
    .then(() => {
    console.log("Data Source has been initialized!");
    app.listen(3000, () => {
      console.log('Auth Microservice is running on port 3000');
    });

  })
  .catch((err) => {
    console.error("Error during Data Source initialization:", err);
  });
Enter fullscreen mode Exit fullscreen mode
Create start script in package.json as below:
"scripts": {
    "test": "echo \"Error: no test specified\" && exit 1", 
    "start": "ts-node ./src/index.ts"
  },
Enter fullscreen mode Exit fullscreen mode

run the application using npm run start
You can access the code from repository

GitHub logo saurabh2k1 / auth-service

Authentication & Authorization Microservice


Part 2 is coming...

Hostinger image

Get n8n VPS hosting 3x cheaper than a cloud solution

Get fast, easy, secure n8n VPS hosting from $4.99/mo at Hostinger. Automate any workflow using a pre-installed n8n application and no-code customization.

Start now

Top comments (0)

Retry later
Retry later