• Stars
    star
    100
  • Rank 340,703 (Top 7 %)
  • Language
    TypeScript
  • Created about 2 years ago
  • Updated about 1 year ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

NextJS + ChakraUI + Prisma + JWT-based Authentication + Two-Factor Authentication + Sentry

NextJS JWT authentication boilerplate

Table of Contents

1. Introduction

This project was developed to show an example of JWT token-based authentication in a Web environment for a research project at the University of Applied Sciences of Southern Switzerland. You can find the related paper here

2. Working demo

Based on this boilerplate, I developed a PWA based on the Chinook database that allows an Employee to view a list of his or her customers.

Demo project link

3. Description

This NextJS 13 boilerplate comes with a fully functional two-factor authentication system based on JWT tokens.

Main features:

  • Sentry error tracking
  • Fully-typed with TypeScript
  • Login with email and password (hashed with bcrypt)
  • Role-based access control (by default: User, Admin)
  • Automatic JWT access token refresh
  • Two-factor authentication via email
  • Front-end useAuth hook to easily manage the user session
  • User session persistence via cookies and local storage
  • New flexible back-end middleware management system
  • Protected routes and pages

4. Tech Stack

5. Getting Started

5.1. Prerequisites

  • Node.js v14.17.0 or higher
  • Yarn v1.22.10 or higher
  • PostgreSQL v13.3 or higher

5.2. Configuration

5.2.1. Install required packages

yarn install

5.2.2. (Optional) Create a new PostgreSQL container with Docker

docker run --name nextjs-jwt-auth -e POSTGRES_PASSWORD=postgres -p 5432:5432 -d postgres

5.2.3. Copy the .env.example file to .env and fill in the required environment variables

cp .env.example .env.local 

5.2.4. Push database schema and seed data to the database

yarn prisma db push && yarn prisma db seed

5.2.5. Start the development server a

yarn dev

6. Authentication flow

The authentication flow is the following:

Authentication flow

The chart is self-explanatory, but to better understand the flow, we can see the following steps:

  1. The user sends a request to the /api/login endpoint, submitting the E-Mail address and password of the user in the request body. The server then validates the user credentials and, if valid, generates a JWT access token and a JWT refresh token. The access token is used to access the protected resources, while the refresh token is used to obtain a new access token when the current access token expires. The access token is sent in the response body, while the refresh token is sent in the response cookies. After that, the server sends an E-Mail to the user with a token used as OTP (one-time password) for the two-factor authentication.

  2. The user cannot access the protected resources until the two-factor authentication in completed.

  3. The user sends a GET request to /api/two-factor passing the two-factor authentication code sent via E-Mail in the request query with name token. The server validates the token and, if valid, the is authenticated and can access the protected resources using the access token generated in step 1. This is a sample two-factor authentication URL:

https://my-awesome-app.com/two-factor?token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MiwiZW1haWwiOiJsdWNhNjQ2OUBnbWFpbC5jb20iLCJuYW1lIjoiSmFuZSIsInN1cm5hbWUiOiJXaGl0ZSIsInJvbGUiOiJBRE1JTiIsImlhdCI6MTY2OTU0Mjk3MiwiZXhwIjoxNjY5NTQzODcyfQ.swKDoKXq72NOzOmRj781_X1EiH2pw2F-BEJiMXkE8xI
  1. The user can now access the protected resources using the access token generated in step 1. The access token is stored inside a cookie named "token".

  2. When the access token expires, the user can obtain a new access token by sending a POST request to the /api/refresh endpoint with a payload containing the refresh token.

{
  "refreshToken": "my-secret-refresh-token"
}

The server then validates the refresh token and, if valid, generates a new access token and updates the user's access token cookie value using Set-Cookie header. This process is done automatically inside the NextJS application by the useAuth hook.

6.1. The useAuth hook

The useAuth hook is a React hook that can be used to easily manage the user session. It is used to authenticate users, to get the user session information, to refresh the access token, to logout users, and to check if the user is authenticated.

The useAuth hook is defined in the providers/auth/AuthProvider.tsx file and is used in the pages/_app.tsx file to wrap the entire application. This is the list of the features provided by the useAuth hook:

  • currentUser: The current user session information, such as the user ID, E-Mail address, name, surname and role
  • accessToken: The JWT access token used to access the protected resources
  • refreshToken: The JWT refresh token used to obtain a new access token when the current access token expires
  • isAuthenticated: A boolean value that indicates if the user is authenticated
  • login(username: string, password: string): A function that can be used to authenticate users
  • logOut(): A function that can be used to logout the user
  • refreshSession(): A function that can be used to refresh the user session

6.2. Route protection

To protect access to the protected resources, have been used two different approaches:

  • Middleware (/middleware.ts) that check if the user has set the access token in the cookies and, if not, redirects the user to the login page

  • Server-side rendering (SSR) function that checks the user's access token validity and, if not valid, redirects the user to the login page

6.3. JWT tokens

The JWT access token and the JWT refresh token have the following payload:

{
  "sub": <user id>,
  "email": <user email>,
  "name": <user first name>,
  "surname": <user last name>,
  "role": <user role: ADMIN or USER>,
  "iat": <issued at timestamp>,
  "exp": <expire at timestamp>,
  "iss": "${APP_URL}", // ENVIRONMENT VARIABLE
}

The JWT access token expires after 15 minutes, while the JWT refresh token expires after 30 days. Both tokens are signed using different secret keys to increase security.

Both tokens shares the same payload structure to permit the server to do extra checks on the token validity. If the user saved in the database is not the same user that is present in the token payload, the token is not valid. This has been done to prevent the user from using a token with old / invalid user information.

7. Screenshots and short demo

Demo video using two accounts at the same time:

demo.mp4

Dashboard page: Dashboard page

Login page:

Login page

Two-factor authentication pages:

Two-Factor authentication landing page: Two-Factor landing page

Two-Factor authentication success page: Two-Factor landing page

Two-Factor authentication error page: Two-Factor landing page

More Repositories

1

in-house-greenhouse

🐛 A new generation of smart indoor greenhouses!
TypeScript
99
star
2

zerotrust-your-home

🔐 Securing Your Digital Sanctuary, Trust None, Protect Everything.
Shell
93
star
3

ImageReader

Using Flask and Tesseract this website is able to read all the text written in an image using OCR (Optical Character Recognition).
JavaScript
16
star
4

it-salary-analysis

💰 Analysis of Salaries in IT Roles: DevOps, Cyber Security, and AI
Jupyter Notebook
13
star
5

SwissJobRightNow

👷🏽 Find a your dream job in Switzerland in very little time using this awesome tool
Python
9
star
6

RimeSegateBot

📸 This telegram bot is able to download videos from remote urls thanks to the embedded youtube-dl library and upload them on OpenLoad or VeryStream
Python
6
star
7

beer-search-engine

🍺 An intuitive beer search engine leveraging PyTerrier and FastAPI, with a user-friendly web interface powered by NextJS and React.js
TypeScript
5
star
8

mmkp

Multiple-choice Multidimensional Knapsack Problem implementation in C++
Jupyter Notebook
4
star
9

nextjs-customer-manager

A NextJS employee manager PWA based on my awesome boilerplate & Chinook DB!
TypeScript
4
star
10

network-attack-detection

Advanced detection of port scanning, DoS and malware attacks using Machine Learning techniques
Jupyter Notebook
4
star
11

VirtualSafe

🔒 Crypt your directories and make your files completely unreadable!
Python
3
star
12

FaceDetection

Face & Eyes detection using Python3 and OpenCV
Python
2
star
13

WeaponizedPing

🔫 A weaponized ping implementation that includes concealed data in the packet payload.
Python
2
star
14

spring-graphql-keycloak-boilerplate

Spring Boot v3 + GraphQL + GraphiQL + KeyCloak boilerplate
Java
1
star
15

dotfiles

A collection of my personal configuration files (dotfiles) for various tools and applications, designed for easy management and synchronization across multiple devices.
Shell
1
star
16

geographical-friendship-network

Simulation of a social network formation influenced by geographical features and distance
Jupyter Notebook
1
star
17

WeatherAdvancedForecast

🌦 Advanced weather forecasts with AI-powered pollution levels prediction
TypeScript
1
star