In this tutorial, we’re gonna build a Node.js Express Login and Registration Rest API example that supports JWT (JSONWebToken) and works with MySQL database. You’ll know:
- Appropriate Flow for User Login and Registration with JWT Authentication
- Node.js Express Architecture with CORS, Authentication & Authorization middlewares & Sequelize
- How to configure Express routes to work with JWT
- How to define Data Models and association for Authentication and Authorization
- Way to use Sequelize to interact with MySQL Database
Related Posts:
– Node.js Express: Login and Registration example with JWT (using HTTP Headers)
– Node.js Rest APIs example with Express, Sequelize & MySQL
– Node.js + MongoDB: User Authentication & Authorization with JWT
– Node.js + PostgreSQL: User Authentication & Authorization with JWT
Fullstack (JWT Authentication & Authorization example):
– Node Express + Vue
– Node Express + Angular 8
– Node Express + Angular 10
– Node Express + Angular 11
– Node Express + Angular 12
– Node Express + Angular 13
– Node Express + Angular 14
– Node Express + Angular 15
– Node Express + Angular 16
– Node Express + React
Deployment:
– Deploying/Hosting Node.js app on Heroku with MySQL database
– Dockerize Node.js Express and MySQL example – Docker Compose
Contents
- Token Based Authentication
- Overview
- Flow
- Architecture
- Technology
- Project Structure
- Create Node.js App
- Setup Express web server
- Configure database & Sequelize
- Define the Sequelize Model
- Initialize Sequelize
- Configure Auth Key
- Create Middleware functions
- Create Controllers
- Define Routes
- Run & Test with Results
- Conclusion
- Source Code
- Further Reading
Token Based Authentication
Comparing with Session-based Authentication that need to store Session on Cookie, the big advantage of Token-based Authentication is that we store the JSON Web Token (JWT) on Client side: Local Storage for Browser, Keychain for IOS and SharedPreferences for Android… So we don’t need to build another backend project that supports Native Apps or an additional Authentication module for Native App users.
There are three important parts of a JWT: Header, Payload, Signature. Together they are combined to a standard structure: header.payload.signature
.
The Client typically attaches JWT in Authorization header with Bearer prefix:
Authorization: Bearer [header].[payload].[signature]
Or in x-access-token header:
x-access-token: [header].[payload].[signature]
Or Cookies:
[name]=[header].[payload].[signature]; Path=/; HttpOnly;
For more details, you can visit:
In-depth Introduction to JWT-JSON Web Token
Overview of Node.js Express Login example
We will build a Node.js Express application in that:
- Authentication: User can signup new account, or login with username & password.
- Authorization: By User’s role (admin, moderator, user), we authorize the User to access resources
These are APIs that we need to provide:
Methods | Urls | Actions |
---|---|---|
POST | /api/auth/signup | signup new account |
POST | /api/auth/signin | login an account |
POST | /api/auth/signout | logout the account |
GET | /api/test/all | retrieve public content |
GET | /api/test/user | access User’s content |
GET | /api/test/mod | access Moderator’s content |
GET | /api/test/admin | access Admin’s content |
Flow for Login and Registration with JWT
The diagram shows flow of User Registration, User Login and Authorization process.
A legal JWT must be stored in Cookies if Client accesses protected resources.
You will need to implement Refresh Token:
More details at: JWT Refresh Token implementation in Node.js example
Node.js Express Login example Architecture
You can have an overview of our Node.js Express App with the diagram below:
Via Express routes, HTTP request that matches a route will be checked by CORS Middleware before coming to Security layer.
Security layer includes:
- JWT Authentication Middleware: verify SignUp, verify token
- Authorization Middleware: check User’s roles with record in database
If these middlewares throw any error, a message will be sent as HTTP response.
Controllers interact with MySQL Database via Sequelize and send HTTP response (token, user information, data based on roles…) to client.
Technology
- Express 4.18.2
- bcryptjs 2.4.3
- cookie-session 2.0.0
- jsonwebtoken 9.0.0
- Sequelize 6.31.1
- MySQL
Project Structure
This is directory structure for our Node.js Express Login and Registration application:
– config
- configure MySQL database & Sequelize
- configure Auth Key
– routes
- auth.routes.js: POST signup, signin & signout
- user.routes.js: GET public & protected resources
– middlewares
- verifySignUp.js: check duplicate Username or Email
- authJwt.js: verify Token, check User roles in database
– controllers
- auth.controller.js: handle signup, signin & signout actions
- user.controller.js: return public & protected content
– models for Sequelize Models
- user.model.js
- role.model.js
– server.js: import and initialize necessary modules and routes, listen for connections.
Create Node.js Express Login App
First, we create a folder for our project:
$ mkdir node-js-express-login-example
$ cd node-js-express-login-example
Then we initialize the Node.js App with a package.json file:
npm init
name: (node-js-express-login-example)
version: (1.0.0)
description: Node.js Express Login and Registration example
entry point: (index.js) server.js
test command:
git repository:
keywords: node.js, express, login, registration, rest api, jwt, authentication, authorization, mysql
author: bezkoder
license: (ISC)
Is this ok? (yes) yes
We need to install necessary modules: express
, cors
, cookie-session
, sequelize
, mysql2
, jsonwebtoken
and bcryptjs
.
Run the command:
npm install express cookie-session sequelize mysql2 cors jsonwebtoken bcryptjs --save
The package.json file now looks like this:
{
"name": "node-js-express-login-example",
"version": "1.0.0",
"description": "Node.js Express Login and Registration example",
"main": "server.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [
"node.js",
"express",
"jwt",
"login",
"registration",
"rest api",
"authentication",
"authorization"
"mysql"
],
"author": "bezkoder",
"license": "ISC",
"dependencies": {
"bcryptjs": "^2.4.3",
"cookie-session": "^2.0.0",
"cors": "^2.8.5",
"express": "^4.18.2",
"jsonwebtoken": "^9.0.0",
"mysql2": "^2.3.3",
"sequelize": "^6.31.1"
}
}
Setup Express web server
In the root folder, let’s create a new server.js file:
const express = require("express");
const cors = require("cors");
const cookieSession = require("cookie-session");
const app = express();
app.use(cors());
// parse requests of content-type - application/json
app.use(express.json());
// parse requests of content-type - application/x-www-form-urlencoded
app.use(express.urlencoded({ extended: true }));
app.use(
cookieSession({
name: "bezkoder-session",
keys: ["COOKIE_SECRET"], // should use as secret environment variable
httpOnly: true,
})
);
// simple route
app.get("/", (req, res) => {
res.json({ message: "Welcome to bezkoder application." });
});
// set port, listen for requests
const PORT = process.env.PORT || 8080;
app.listen(PORT, () => {
console.log(`Server is running on port ${PORT}.`);
});
Let me explain what we’ve just done:
– import express
, cookie-session
and cors
modules:
- Express is for building the Rest apis
- cookie-session helps to stores the session data on the client within a cookie without requiring any database/resources on the server side
- cors provides Express middleware to enable CORS
– create an Express app, then add request parsing, cookie-based session middleware and cors
middlewares using app.use()
method.
– define a GET route which is simple for test.
– listen on port 8080 for incoming requests.
Let’s talk about following code:
app.use(
cookieSession({
name: "bezkoder-session",
// keys: ['key1', 'key2'],
secret: "COOKIE_SECRET", // should use as secret environment variable
httpOnly: true
})
);
keys
: sign & verify cookie values. Set cookies are always signed withkeys[0]
, while the other keys are valid for verification, allowing for key rotation.secret
: we don’t providekeys
, so we use this as single key. In practice, you must provide value as secret environment variable (.env
file for example) for security.httpOnly
: indicate that the cookie is only to be sent over HTTP(S), and not made available to client JavaScript.
Now let’s run the app with command: node server.js
.
Open your browser with url http://localhost:8080/, you will see:
Configure MySQL database & Sequelize
In the app folder, create config folder for configuration with db.config.js file like this:
module.exports = {
HOST: "localhost",
USER: "root",
PASSWORD: "123456",
DB: "testdb",
dialect: "mysql",
pool: {
max: 5,
min: 0,
acquire: 30000,
idle: 10000
}
};
First five parameters are for MySQL connection.
pool
is optional, it will be used for Sequelize connection pool configuration:
max
: maximum number of connection in poolmin
: minimum number of connection in poolidle
: maximum time, in milliseconds, that a connection can be idle before being releasedacquire
: maximum time, in milliseconds, that pool will try to get connection before throwing error
For more details, please visit API Reference for the Sequelize constructor.
Define the Sequelize Model
In models folder, create User
and Role
data model as following code:
models/user.model.js
module.exports = (sequelize, Sequelize) => {
const User = sequelize.define("users", {
username: {
type: Sequelize.STRING
},
email: {
type: Sequelize.STRING
},
password: {
type: Sequelize.STRING
}
});
return User;
};
models/role.model.js
module.exports = (sequelize, Sequelize) => {
const Role = sequelize.define("roles", {
id: {
type: Sequelize.INTEGER,
primaryKey: true
},
name: {
type: Sequelize.STRING
}
});
return Role;
};
These Sequelize Models represents users & roles table in MySQL database.
After initializing Sequelize, we don’t need to write CRUD functions, Sequelize supports all of them:
- create a new User:
create(object)
- find a User by id:
findByPk(id)
- find a User by email:
findOne({ where: { email: ... } })
- get all Users:
findAll()
- find all Users by username:
findAll({ where: { username: ... } })
These functions will be used in our Controllers and Middlewares.
Initialize Sequelize
Now create app/models/index.js with content like this:
const config = require("../config/db.config.js");
const Sequelize = require("sequelize");
const sequelize = new Sequelize(
config.DB,
config.USER,
config.PASSWORD,
{
host: config.HOST,
dialect: config.dialect,
pool: {
max: config.pool.max,
min: config.pool.min,
acquire: config.pool.acquire,
idle: config.pool.idle
}
}
);
const db = {};
db.Sequelize = Sequelize;
db.sequelize = sequelize;
db.user = require("../models/user.model.js")(sequelize, Sequelize);
db.role = require("../models/role.model.js")(sequelize, Sequelize);
db.role.belongsToMany(db.user, {
through: "user_roles"
});
db.user.belongsToMany(db.role, {
through: "user_roles"
});
db.ROLES = ["user", "admin", "moderator"];
module.exports = db;
The association between Users and Roles is Many-to-Many relationship:
– One User can have several Roles.
– One Role can be taken on by many Users.
We use User.belongsToMany(Role)
to indicate that the user model can belong to many Roles and vice versa.
With through
parameter, we’re gonna have a new table user_roles as connection between users and roles table via their primary key as foreign keys.
If you want to know more details about how to make Many-to-Many Association with Sequelize and Node.js, please visit:
Sequelize Many-to-Many Association example – Node.js & MySQL
Don’t forget to call sync()
method in server.js.
...
const app = express();
app.use(...);
const db = require("./app/models");
const Role = db.role;
db.sequelize.sync({force: true}).then(() => {
console.log('Drop and Resync Db');
initial();
});
...
function initial() {
Role.create({
id: 1,
name: "user"
});
Role.create({
id: 2,
name: "moderator"
});
Role.create({
id: 3,
name: "admin"
});
}
initial()
function helps us to create 3 rows in database.
In development, you may need to drop existing tables and re-sync database. So you can use force: true
as code above.
For production, just insert these rows manually and use sync()
without parameters to avoid dropping data:
...
const app = express();
app.use(...);
const db = require("./app/models");
db.sequelize.sync();
...
Learn how to implement Sequelize One-to-Many Relationship at:
Sequelize Associations: One-to-Many example – Node.js, MySQL
Configure Auth Key
jsonwebtoken functions such as verify()
or sign()
use algorithm that needs a secret key (as String) to encode and decode token.
In the app/config folder, create auth.config.js file with following code:
module.exports = {
secret: "bezkoder-secret-key"
};
You can create your own secret
String.
Create Middleware functions
To verify a Signup (registration) action, we need 2 functions:
– check if username
or email
is duplicate or not
– check if roles
in the request is existed or not
middleware/verifySignUp.js
const db = require("../models");
const ROLES = db.ROLES;
const User = db.user;
checkDuplicateUsernameOrEmail = async (req, res, next) => {
try {
// Username
let user = await User.findOne({
where: {
username: req.body.username
}
});
if (user) {
return res.status(400).send({
message: "Failed! Username is already in use!"
});
}
// Email
user = await User.findOne({
where: {
email: req.body.email
}
});
if (user) {
return res.status(400).send({
message: "Failed! Email is already in use!"
});
}
next();
} catch (error) {
return res.status(500).send({
message: "Unable to validate Username!"
});
}
};
checkRolesExisted = (req, res, next) => {
if (req.body.roles) {
for (let i = 0; i < req.body.roles.length; i++) {
if (!ROLES.includes(req.body.roles[i])) {
res.status(400).send({
message: "Failed! Role does not exist = " + req.body.roles[i]
});
return;
}
}
}
next();
};
const verifySignUp = {
checkDuplicateUsernameOrEmail,
checkRolesExisted
};
module.exports = verifySignUp;
To process Authentication & Authorization, we have these functions:
- check if token
is provided, legal or not. We get token from session of HTTP request object, then use jsonwebtoken's verify()
function.
- check if roles
of the user contains required role or not.
middleware/authJwt.js
const jwt = require("jsonwebtoken");
const config = require("../config/auth.config.js");
const db = require("../models");
const User = db.user;
verifyToken = (req, res, next) => {
let token = req.session.token;
if (!token) {
return res.status(403).send({
message: "No token provided!",
});
}
jwt.verify(token,
config.secret,
(err, decoded) => {
if (err) {
return res.status(401).send({
message: "Unauthorized!",
});
}
req.userId = decoded.id;
next();
});
};
isAdmin = async (req, res, next) => {
try {
const user = await User.findByPk(req.userId);
const roles = await user.getRoles();
for (let i = 0; i < roles.length; i++) {
if (roles[i].name === "admin") {
return next();
}
}
return res.status(403).send({
message: "Require Admin Role!",
});
} catch (error) {
return res.status(500).send({
message: "Unable to validate User role!",
});
}
};
isModerator = async (req, res, next) => {
try {
const user = await User.findByPk(req.userId);
const roles = await user.getRoles();
for (let i = 0; i < roles.length; i++) {
if (roles[i].name === "moderator") {
return next();
}
}
return res.status(403).send({
message: "Require Moderator Role!",
});
} catch (error) {
return res.status(500).send({
message: "Unable to validate Moderator role!",
});
}
};
isModeratorOrAdmin = async (req, res, next) => {
try {
const user = await User.findByPk(req.userId);
const roles = await user.getRoles();
for (let i = 0; i < roles.length; i++) {
if (roles[i].name === "moderator") {
return next();
}
if (roles[i].name === "admin") {
return next();
}
}
return res.status(403).send({
message: "Require Moderator or Admin Role!",
});
} catch (error) {
return res.status(500).send({
message: "Unable to validate Moderator or Admin role!",
});
}
};
const authJwt = {
verifyToken,
isAdmin,
isModerator,
isModeratorOrAdmin,
};
module.exports = authJwt;
middleware/index.js
const authJwt = require("./authJwt");
const verifySignUp = require("./verifySignUp");
module.exports = {
authJwt,
verifySignUp
};
Create Controllers
Controller for Registration, Login, Logout
There are 3 main functions for Login and Registration:
- signup
: create new User in database (role is user if not specifying role)
- signin
:
- find
username
of the request in database, if it exists - compare
password
withpassword
in database using bcrypt, if it is correct - generate a token using jsonwebtoken
- return user information & access Token in Cookies
- signout
: clear session.
controllers/auth.controller.js
const db = require("../models");
const config = require("../config/auth.config");
const User = db.user;
const Role = db.role;
const Op = db.Sequelize.Op;
const jwt = require("jsonwebtoken");
const bcrypt = require("bcryptjs");
exports.signup = async (req, res) => {
// Save User to Database
try {
const user = await User.create({
username: req.body.username,
email: req.body.email,
password: bcrypt.hashSync(req.body.password, 8),
});
if (req.body.roles) {
const roles = await Role.findAll({
where: {
name: {
[Op.or]: req.body.roles,
},
},
});
const result = user.setRoles(roles);
if (result) res.send({ message: "User registered successfully!" });
} else {
// user has role = 1
const result = user.setRoles([1]);
if (result) res.send({ message: "User registered successfully!" });
}
} catch (error) {
res.status(500).send({ message: error.message });
}
};
exports.signin = async (req, res) => {
try {
const user = await User.findOne({
where: {
username: req.body.username,
},
});
if (!user) {
return res.status(404).send({ message: "User Not found." });
}
const passwordIsValid = bcrypt.compareSync(
req.body.password,
user.password
);
if (!passwordIsValid) {
return res.status(401).send({
message: "Invalid Password!",
});
}
const token = jwt.sign({ id: user.id },
config.secret,
{
algorithm: 'HS256',
allowInsecureKeySizes: true,
expiresIn: 86400, // 24 hours
});
let authorities = [];
const roles = await user.getRoles();
for (let i = 0; i < roles.length; i++) {
authorities.push("ROLE_" + roles[i].name.toUpperCase());
}
req.session.token = token;
return res.status(200).send({
id: user.id,
username: user.username,
email: user.email,
roles: authorities,
});
} catch (error) {
return res.status(500).send({ message: error.message });
}
};
exports.signout = async (req, res) => {
try {
req.session = null;
return res.status(200).send({
message: "You've been signed out!"
});
} catch (err) {
this.next(err);
}
};
Controller for testing Authorization
There are 4 functions:
– /api/test/all
for public access
– /api/test/user
for loggedin users (role: user/moderator/admin)
– /api/test/mod
for users having moderator role
– /api/test/admin
for users having admin role
controllers/user.controller.js
exports.allAccess = (req, res) => {
res.status(200).send("Public Content.");
};
exports.userBoard = (req, res) => {
res.status(200).send("User Content.");
};
exports.adminBoard = (req, res) => {
res.status(200).send("Admin Content.");
};
exports.moderatorBoard = (req, res) => {
res.status(200).send("Moderator Content.");
};
Now, do you have any question? Would you like to know how we can combine middlewares with controller functions?
Let's do it in the next section.
Define Routes
When a client sends request for an endpoint using HTTP request (GET, POST, PUT, DELETE), we need to determine how the server will response by setting up the routes.
We can separate our routes into 2 part: for Authentication and for Authorization (accessing protected resources).
Authentication:
- POST
/api/auth/signup
- POST
/api/auth/signin
- POST
/api/auth/signout
routes/auth.routes.js
const { verifySignUp } = require("../middleware");
const controller = require("../controllers/auth.controller");
module.exports = function(app) {
app.use(function(req, res, next) {
res.header(
"Access-Control-Allow-Headers",
"Origin, Content-Type, Accept"
);
next();
});
app.post(
"/api/auth/signup",
[
verifySignUp.checkDuplicateUsernameOrEmail,
verifySignUp.checkRolesExisted
],
controller.signup
);
app.post("/api/auth/signin", controller.signin);
app.post("/api/auth/signout", controller.signout);
};
Authorization:
- GET
/api/test/all
- GET
/api/test/user
for loggedin users (user/moderator/admin) - GET
/api/test/mod
for moderator - GET
/api/test/admin
for admin
routes/user.routes.js
const { authJwt } = require("../middleware");
const controller = require("../controllers/user.controller");
module.exports = function(app) {
app.use(function(req, res, next) {
res.header(
"Access-Control-Allow-Headers",
"Origin, Content-Type, Accept"
);
next();
});
app.get("/api/test/all", controller.allAccess);
app.get(
"/api/test/user",
[authJwt.verifyToken],
controller.userBoard
);
app.get(
"/api/test/mod",
[authJwt.verifyToken, authJwt.isModerator],
controller.moderatorBoard
);
app.get(
"/api/test/admin",
[authJwt.verifyToken, authJwt.isAdmin],
controller.adminBoard
);
};
Don't forget to add these routes in server.js:
...
// routes
require('./app/routes/auth.routes')(app);
require('./app/routes/user.routes')(app);
// set port, listen for requests
...
Run & Test with Results
Run Node.js application with command: node server.js
Tables that we define in models package will be automatically generated in MySQL Database.
If you check the database, you can see things like this:
mysql> describe users;
+-----------+--------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-----------+--------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| username | varchar(255) | YES | | NULL | |
| email | varchar(255) | YES | | NULL | |
| password | varchar(255) | YES | | NULL | |
| createdAt | datetime | NO | | NULL | |
| updatedAt | datetime | NO | | NULL | |
+-----------+--------------+------+-----+---------+----------------+
mysql> describe roles;
+-----------+--------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-----------+--------------+------+-----+---------+-------+
| id | int(11) | NO | PRI | NULL | |
| name | varchar(255) | YES | | NULL | |
| createdAt | datetime | NO | | NULL | |
| updatedAt | datetime | NO | | NULL | |
+-----------+--------------+------+-----+---------+-------+
mysql> describe user_roles;
+-----------+----------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-----------+----------+------+-----+---------+-------+
| createdAt | datetime | NO | | NULL | |
| updatedAt | datetime | NO | | NULL | |
| roleId | int(11) | NO | PRI | NULL | |
| userId | int(11) | NO | PRI | NULL | |
+-----------+----------+------+-----+---------+-------+
If you don't use initial()
function in Sequelize sync()
method. You need to run following SQL script:
mysql> INSERT INTO roles VALUES (1, 'user', now(), now());
mysql> INSERT INTO roles VALUES (2, 'moderator', now(), now());
mysql> INSERT INTO roles VALUES (3, 'admin', now(), now());
3 records will be created in roles
table:
mysql> select * from roles;
+----+-----------+---------------------+---------------------+
| id | name | createdAt | updatedAt |
+----+-----------+---------------------+---------------------+
| 1 | user | 2021-11-13 09:05:39 | 2021-11-13 09:05:39 |
| 2 | moderator | 2021-11-13 09:05:39 | 2021-11-13 09:05:39 |
| 3 | admin | 2021-11-13 09:05:39 | 2021-11-13 09:05:39 |
+----+-----------+---------------------+---------------------+
Register some users with /signup
API:
- admin with
admin
role - mod with
moderator
anduser
roles - zkoder with
user
role
Our tables after signup could look like this.
mysql> select * from users;
+----+----------+--------------------+--------------------------------------------------------------+---------------------+---------------------+
| id | username | email | password | createdAt | updatedAt |
+----+----------+--------------------+--------------------------------------------------------------+---------------------+---------------------+
| 1 | admin | [email protected] | $2a$08$w3cYCF.N0UQZO19z8CQSZ.whzxFS5vMoi9k51g3TQx9r5tkwrIXO2 | 2021-11-13 09:21:51 | 2021-11-13 09:21:51 |
| 2 | mod | [email protected] | $2a$08$tTj1l28esAxPSSvl3YqKl./nz35vQF7Y76jGtzcYUhHtGy6d.1/ze | 2021-11-13 09:22:01 | 2021-11-13 09:22:01 |
| 3 | zkoder | [email protected] | $2a$08$U2F07dLyYZjzTxQbFMCAcOd1k8V1o9f6E4TGVJHpy0V6/DC7iS0CS | 2021-11-13 09:23:25 | 2021-11-13 09:23:25 |
+----+----------+--------------------+--------------------------------------------------------------+---------------------+---------------------+
mysql> select * from user_roles;
+---------------------+---------------------+--------+--------+
| createdAt | updatedAt | roleId | userId |
+---------------------+---------------------+--------+--------+
| 2021-11-13 09:22:01 | 2021-11-13 09:22:01 | 1 | 2 |
| 2021-11-13 09:23:25 | 2021-11-13 09:23:25 | 1 | 3 |
| 2021-11-13 09:22:01 | 2021-11-13 09:22:01 | 2 | 2 |
| 2021-11-13 09:21:51 | 2021-11-13 09:21:51 | 3 | 1 |
+---------------------+---------------------+--------+--------+
Access public resource: GET /api/test/all
Access protected resource: GET /api/test/user
Login an account (with wrong password): POST /api/auth/signin
(Remember to set Content-Type: application/json
on request Headers)
Login an account: POST /api/auth/signin
You can check the Cookies with JWT:
Access protected resources
- GET /api/test/user
- GET /api/test/mod
- GET /api/test/admin
Conclusion
Congratulation!
Today we've learned so many interesting things about Node.js Express Login and Registration example with JWT - JSONWebToken by building Rest Apis for Authentication and Authorization.
Despite we wrote a lot of code, I hope you will understand the overall architecture of the application, and apply it in your project at ease.
You should continue to know how to implement Refresh Token:
JWT Refresh Token implementation in Node.js example
If you need a working front-end for this back-end, you can find Client App in the post:
- Angular 12 / Angular 13 / Angular 14 / Angular 15 / Angular 16
- React / React Redux
Related Post:
Node.js Express: Login and Registration example with JWT (using HTTP Headers)
Happy learning! See you again.
Further Reading
- https://www.npmjs.com/package/express
- http://expressjs.com/en/guide/routing.html
- In-depth Introduction to JWT-JSON Web Token
- Sequelize Associations
Fullstack CRUD Application:
- Vue.js + Node.js + Express + MySQL example
- Angular 8 + Node.js Express + MySQL example
- Angular 10 + Node.js Express + MySQL example
- Angular 11 + Node.js Express + MySQL example
- Angular 12 + Node.js Express + MySQL example
- Angular 13 + Node.js Express + MySQL example
- Angular 14 + Node.js Express + MySQL example
- Angular 15 + Node.js Express + MySQL example
- Angular 16 + Node.js Express + MySQL example
- React + Node.js + Express + MySQL example
Deployment:
- Deploying/Hosting Node.js app on Heroku with MySQL database
- Dockerize Node.js Express and MySQL example – Docker Compose
Source Code
You can find the complete source code for this tutorial on Github.
this is beyond bootcamp level
What else can I say…except Thank you for sharing this in-depth tutorial. You are Amazing bro… YOU ARE AMAZING. Thank you so dearly.
I was suggested this Node tutorial by my friend. You are amazing! Thanks!
Greetings! Many thanks for writing this tutorial!
Excellent tutorial!
Thank you for this fantastic tutorial.