Node Express Typescript Authentication Boilerplate
This is a boilerplate/starter project to start building a production/staging/development environment ready REST API's based on Express.js and Typescript.
This app comes with many build-in features like JWT, authentication, authorization, different security middleware to sanitize requests, logging, testing, Swagger documentation, error handling and deploy applications with few command as Docker Container or Kubernetes and automation of testing and building using GitHub Actions. You can build your application on top of these features already configured.
This application leverages technologies like Node.js, Express, Typescript MongoDB, Redis/Redis Cluster, JWT, Docker, Docker Hub, Kubernetes, CI/CD using GitHub Action. This application is build with the mindset of maintaining industry good practices of developing Node.js Express app with Typescript.
Table of contents
- Quick Start
- Features
- Project Structure
- Environment Variables
- API Documentation
- API Endpoints
- Testing
- CI using GitHub Actions
- Deployment Process
- Authentication and Authorization Flow
- Forgot Password Flow
- Client Application Creation
- Conclusion
Quick Start
To get started with the project quickly do these steps
Clone the repo:
git clone https://github.com/faizul-mustafiz/node-express-auth-typescript-boilerplate.git
Install the dependencies:
npm install
# OR
npm ci
Set the environment variables:
To run the project set up the environment variables. An env.example file is present listing the necessary variables of the project.
Make new file name .env at the root of the project and edit them with your config.
Run the project locally:
npm start
Features
- Dependency Management: with npm
- Database: MongoDB Atlas with object data modeling wing Mongoose
- Cache Database: Redis with object data modeling wing Mongoose
- **Authentication and Authorization:**Custom implementation of JWT
- Validation: request data validation using Joi
- Logging: using Winston and Morgan
- Testing: using Mocha and Chai.js
- Error Handling: Centralized error handling with base error handler class and other errors extending base error handler class
- API documentation: with OpenAPI 3.0 specification using Swagger and swagger-ui-express
- Environment variables: using dotenv
- Security: Implementation of API Key and API secret with only trusted application validation and device info encryption using API secret with json-ed-aes package
- CORS: Cross-Origin Resource-Sharing enabled using cors
- CI: continuous integration with GitHub Actions
- Containerization: using Docker or and as image repository
Project Structure
|--.github # github action config files
|--.husky # github hooks config files
|--deployments # kubernetes config files
|--docker-compose # docker compose config files
|--src\v1
|--configs\ # config of plugins and environments
|--controllers\ # route controller functions
|--docs\ # swagger documentation files
|--enums\ # required enums
|--environments\ # different types of environment configuration
|--errors\ # Error handling files fro different types of error
|--generators\ # generator functions of different values
|--helpers\ # route controller helpers functions
|--logger\ # base logger and file logger config files
|--middlewares\ # express middlewares related to auth and validation
|--nginx\ # docker configs and docker file for nginx
|--plugins\ # plugins for project like redis and mongodb
|--responses\ # success response object builder
|--routes\ # route definitions
|--test\ # unit test definition functions
|--utility\ # utility functions
|--validators\ # request validator functions
|--app.ts # express application init and injections
|--.dockerignore # docker ignore lists
|--.env.example # env file example
|--.gitignore # git ignore list
|--.mocharc.json # mocha config
|--.prettierignore # prettier ignore list
|--.prettierrc # prettier config
|--index.ts # application entry point, server, shutdown
|--package-lock.json
|--package.json
|--README.md
Environment Variables
The environment variables example can be found in .env.example and edit these fields in .env file
#app environment variables
API_PROTOCOL="http"
API_HOST="0.0.0.0"
API_PORT=3030
BASE_API_ROUTE="/api/v1"
# redis environment variables
# this url is for redis configured is redis-Labs/docker container/Kubernetes cluster
REDIS_URL="your-redis-labs-connection-string"
# redis test environment variables
REDIS_URL_TEST="your-redis-test-db-connection-string"
# mongodb environment variables
MONGO_URL="your-mongo-connection-string"
# mongodb test environment variables
MONGO_URL_TEST="your-mongo-test-db-connection-string"
# JWT environment variables
ACCESS_TOKEN_EXPIRY_TIME=10800
REFRESH_TOKEN_EXPIRY_TIME=43200
VERIFY_TOKEN_SECRET="Your verify token secret"
VERIFY_TOKEN_EXPIRY_TIME=3600
CHANGE_PASSWORD_TOKEN_SECRET="Your change password token secret"
CHANGE_PASSWORD_TOKEN_EXPIRY_TIME=3600
PUBLIC_KEY="your-public-key"
PRIVATE_KEY="your-private-Key"
there is a generator file /src/v1/generators/key.generator.ts you can generate JWT keys form here. The JWT encryption and decryption is based on { algorithm: 'ES512' } so you need to generate public key and private key using openssl commands.
Run this commands to generate a private key and public key and then update the .env file with those keys.
# For PRIVATE_KEY
openssl ecparam -genkey -name secp521r1 -noout -out private-key-name.pem
# For PRIVATE_KEY
openssl ec -in private-key-name.pem -pubout -out public-key-name.pem
# To get the keys
cat private-key-name.pem
cat public-key-name.pem
API Documentation
Documentation is available at http://{host}:{port}/v1/docs you can see the schema definition and routes definition and response definition with examples. Test the API endpoints from here as well.
API Endpoints
Auth
[POST] sign-up: http://{host}:{port}/api/v1/auth/sign-up
[POST] sign-in: http://{host}:{port}/api/v1/auth/sign-in
[POST] sign-out: http://{host}:{port}/api/v1/auth/sign-out
[POST] verify: http://{host}:{port}/api/v1/auth/verify
[POST] forgot-password: http://{host}:{port}/api/v1/auth/forgot-password
[POST] change-password: http://{host}:{port}/api/v1/auth/change-password
[POST] refresh: http://{host}:{port}/api/v1/auth/refresh
[POST] revoke-access-token: http://{host}:{port}/api/v1/auth/revoke-at
[POST] revoke-refresh-token: http://{host}:{port}/api/v1/auth/revoke-rt
Users
[GET] get-all-user: http://{host}:{port}/api/v1/users
[GET] get-one-user: http://{host}:{port}/api/v1/users/{userId}
[POST] update-one-user: http://{host}:{port}/api/v1/users/{userId}
[DELETE] delete-one-user: http://{host}:{port}/api/v1/users/{userId}
Applications
[GET] get-all-application: http://{host}:{port}/api/v1/applications
[GET] get-one-application: http://{host}:{port}/api/v1/applications/{appId}
[POST] update-one-application: http://{host}:{port}/api/v1/applications/{appId}
[DELETE] delete-one-application: http://{host}:{port}/api/v1/applications/{appId}
Testing
By default the application is tested before every commit using github hooks and while performing CI integration using github actions.
For testing Mocha and Chai.js is used. you can see the test command in package.json file.
Note: You need to add two keys in .env file REDIS_TEST_URL and MONGO_TEST_URL as the test files deletes all the collection data in mongo for test purpose and flush redis db for redis data. So if you do this on your main collection or redis then you will lose all data after test.
Run this command to test manually
npm test
CI using GitHub Actions
Continues Integration is performed using github actions. Go inside the .github/workflows directory and see inside auth-app.ci.dev.yaml.
This workflow has two major jobs
- Run test
- push image to Docker-Hub`
You need to add multiple repository secrets to pass the build arguments and docker hub credentials for this docker-hub image push.
These are the secrets you need to add in github to run the workflow
secrets.DOCKERHUB_USERNAME # Docker hub username
secrets.DOCKERHUB_TOKEN # Docker hub token
secrets.API_PORT # app running port
secrets.API_HOST # app host name
secrets.BASE_API_ROUTE # app base route
secrets.REDIS_URL # redis db/index url for app
secrets.REDIS_URL_TEST # redis deb/index url for test
secrets.MONGO_URL # mongo main db url
secrets.MONGO_URL_TEST # mongo test db url
secrets.ACCESS_TOKEN_EXPIRY_TIME # access token expiry time
secrets.REFRESH_TOKEN_EXPIRY_TIME # refresh token expiry time
secrets.VERIFY_TOKEN_SECRET # verify token secret
secrets.VERIFY_TOKEN_EXPIRY_TIME # verify token expiry time
secrets.CHANGE_PASSWORD_TOKEN_SECRET # change password token secret
secrets.CHANGE_PASSWORD_TOKEN_EXPIRY_TIME # change password token expiry time
secrets.PUBLIC_KEY # access and refresh token public key for
({algorithm: 'ES512' })
secrets.PRIVATE_KEY # access and refresh token private key for
({algorithm: 'ES512' })
Deployment Process
Using Docker Compose
The base Dockerfile is configured for GitHub Actions as all the environment variables are passed as build arguments from github repository secrets. Use the Dockerfile inside docker-compose directory.
docker-compose.yaml file pulls application image from docker hub. if you want to build and run image form locally you need to update the docker-compose.yaml file
the compose file will start redis, application and nginx inside same network and there are 4 instance of application which is load balanced inside nginx config. You will also need to update the .env file key REDIS_URL with docker container url.
MongoDB Atlas is used so just need to update the MONGO_URL key in .env
Now run docker compo