diff --git a/.gitignore b/.gitignore deleted file mode 100644 index 25c8fdb..0000000 --- a/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -node_modules -package-lock.json \ No newline at end of file diff --git a/README.md b/README.md deleted file mode 100644 index 1b4ecc8..0000000 --- a/README.md +++ /dev/null @@ -1,65 +0,0 @@ -# Node.js – JWT Authentication example with PostgreSQL example - -## User Registration, User Login and Authorization process. -The diagram shows flow of how we implement User Registration, User Login and Authorization process. - -![jwt-token-authentication-node-js-example-flow](jwt-token-authentication-node-js-example-flow.png) - -For more detail, please visit: -> [Node.js JWT Authentication & Authorization with PostgreSQL example](https://www.bezkoder.com/node-js-jwt-authentication-postgresql/) - -You may need to implement Refresh Token: - -![jwt-refresh-token-node-js-example-flow](jwt-refresh-token-node-js-example-flow.png) - -> [Node.js JWT Refresh Token example](https://www.bezkoder.com/jwt-refresh-token-node-js/) - -Working with Front-end: -> [Vue.js JWT Authentication with Vuex and Vue Router](https://www.bezkoder.com/jwt-vue-vuex-authentication/) - -> [Angular 8 JWT Authentication example](https://www.bezkoder.com/angular-jwt-authentication/) - -> [Angular 10 JWT Authentication example](https://www.bezkoder.com/angular-10-jwt-auth/) - -> [Angular 11 JWT Authentication example](https://www.bezkoder.com/angular-11-jwt-auth/) - -> [Angular 12 JWT Authentication example](https://www.bezkoder.com/angular-12-jwt-auth/) - -> [Angular 13 JWT Authentication example](https://www.bezkoder.com/angular-13-jwt-auth/) - -> [React JWT Authentication & Authorization (without Redux) example](https://www.bezkoder.com/react-jwt-auth/) - -> [React Redux JWT Authentication & Authorization example](https://www.bezkoder.com/react-redux-jwt-auth/) - -## More Practice: -> [Node.js CRUD Rest APIs with Express, Sequelize & PostgreSQL example](https://www.bezkoder.com/node-express-sequelize-postgresql/) - -> [Node.js Express Pagination with PostgreSQL example](https://www.bezkoder.com/node-js-pagination-postgresql/) - -> [Node.js Express File Upload Rest API example](https://www.bezkoder.com/node-js-express-file-upload/) - -> [Node.js Express File Upload with Google Cloud Storage example](https://www.bezkoder.com/google-cloud-storage-nodejs-upload-file/) - -Associations: -> [Sequelize Associations: One-to-Many Relationship example](https://www.bezkoder.com/sequelize-associate-one-to-many/) - -> [Sequelize Associations: Many-to-Many Relationship example](https://www.bezkoder.com/sequelize-associate-many-to-many/) - -Integration on same Server/Port: -> [Integrate Vue with Node.js Express](https://www.bezkoder.com/serve-vue-app-express/) - -> [Integrate Angular with Node.js Express](https://www.bezkoder.com/integrate-angular-12-node-js/) - -> [Integrate React with Node.js Express](https://www.bezkoder.com/integrate-react-express-same-server-port/) - -## Project setup -``` -npm install -``` - -Then, edit `app/config/db.config.js` with correct DB credentials. - -### Run -``` -node server.js -``` diff --git a/app/config/auth.config.js b/app/config/auth.config.js deleted file mode 100644 index 4819df3..0000000 --- a/app/config/auth.config.js +++ /dev/null @@ -1,3 +0,0 @@ -module.exports = { - secret: "bezkoder-secret-key" -}; diff --git a/app/config/db.config.js b/app/config/db.config.js deleted file mode 100644 index d186745..0000000 --- a/app/config/db.config.js +++ /dev/null @@ -1,13 +0,0 @@ -module.exports = { - HOST: "localhost", - USER: "postgres", - PASSWORD: "123", - DB: "testdb", - dialect: "postgres", - pool: { - max: 5, - min: 0, - acquire: 30000, - idle: 10000 - } -}; \ No newline at end of file diff --git a/app/controllers/auth.controller.js b/app/controllers/auth.controller.js deleted file mode 100644 index 4dc09f6..0000000 --- a/app/controllers/auth.controller.js +++ /dev/null @@ -1,91 +0,0 @@ -const db = require("../models"); -const config = require("../config/auth.config"); -const User = db.user; -const Role = db.role; - -const Op = db.Sequelize.Op; - -var jwt = require("jsonwebtoken"); -var bcrypt = require("bcryptjs"); - -exports.signup = (req, res) => { - // Save User to Database - User.create({ - username: req.body.username, - email: req.body.email, - password: bcrypt.hashSync(req.body.password, 8) - }) - .then(user => { - if (req.body.roles) { - Role.findAll({ - where: { - name: { - [Op.or]: req.body.roles - } - } - }).then(roles => { - user.setRoles(roles).then(() => { - res.send({ message: "User registered successfully!" }); - }); - }); - } else { - // user role = 1 - user.setRoles([1]).then(() => { - res.send({ message: "User registered successfully!" }); - }); - } - }) - .catch(err => { - res.status(500).send({ message: err.message }); - }); -}; - -exports.signin = (req, res) => { - User.findOne({ - where: { - username: req.body.username - } - }) - .then(user => { - if (!user) { - return res.status(404).send({ message: "User Not found." }); - } - - var passwordIsValid = bcrypt.compareSync( - req.body.password, - user.password - ); - - if (!passwordIsValid) { - return res.status(401).send({ - accessToken: null, - message: "Invalid Password!" - }); - } - - const token = jwt.sign({ id: user.id }, - config.secret, - { - algorithm: 'HS256', - allowInsecureKeySizes: true, - expiresIn: 86400, // 24 hours - }); - - var authorities = []; - user.getRoles().then(roles => { - for (let i = 0; i < roles.length; i++) { - authorities.push("ROLE_" + roles[i].name.toUpperCase()); - } - res.status(200).send({ - id: user.id, - username: user.username, - email: user.email, - roles: authorities, - accessToken: token - }); - }); - }) - .catch(err => { - res.status(500).send({ message: err.message }); - }); -}; diff --git a/app/controllers/user.controller.js b/app/controllers/user.controller.js deleted file mode 100644 index e2fa15b..0000000 --- a/app/controllers/user.controller.js +++ /dev/null @@ -1,15 +0,0 @@ -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."); -}; diff --git a/app/middleware/authJwt.js b/app/middleware/authJwt.js deleted file mode 100644 index ccb5605..0000000 --- a/app/middleware/authJwt.js +++ /dev/null @@ -1,91 +0,0 @@ -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.headers["x-access-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 = (req, res, next) => { - User.findByPk(req.userId).then(user => { - user.getRoles().then(roles => { - for (let i = 0; i < roles.length; i++) { - if (roles[i].name === "admin") { - next(); - return; - } - } - - res.status(403).send({ - message: "Require Admin Role!" - }); - return; - }); - }); -}; - -isModerator = (req, res, next) => { - User.findByPk(req.userId).then(user => { - user.getRoles().then(roles => { - for (let i = 0; i < roles.length; i++) { - if (roles[i].name === "moderator") { - next(); - return; - } - } - - res.status(403).send({ - message: "Require Moderator Role!" - }); - }); - }); -}; - -isModeratorOrAdmin = (req, res, next) => { - User.findByPk(req.userId).then(user => { - user.getRoles().then(roles => { - for (let i = 0; i < roles.length; i++) { - if (roles[i].name === "moderator") { - next(); - return; - } - - if (roles[i].name === "admin") { - next(); - return; - } - } - - res.status(403).send({ - message: "Require Moderator or Admin Role!" - }); - }); - }); -}; - -const authJwt = { - verifyToken: verifyToken, - isAdmin: isAdmin, - isModerator: isModerator, - isModeratorOrAdmin: isModeratorOrAdmin -}; -module.exports = authJwt; diff --git a/app/middleware/index.js b/app/middleware/index.js deleted file mode 100644 index 78a3414..0000000 --- a/app/middleware/index.js +++ /dev/null @@ -1,7 +0,0 @@ -const authJwt = require("./authJwt"); -const verifySignUp = require("./verifySignUp"); - -module.exports = { - authJwt, - verifySignUp -}; diff --git a/app/middleware/verifySignUp.js b/app/middleware/verifySignUp.js deleted file mode 100644 index 2e2e030..0000000 --- a/app/middleware/verifySignUp.js +++ /dev/null @@ -1,57 +0,0 @@ -const db = require("../models"); -const ROLES = db.ROLES; -const User = db.user; - -checkDuplicateUsernameOrEmail = (req, res, next) => { - // Username - User.findOne({ - where: { - username: req.body.username - } - }).then(user => { - if (user) { - res.status(400).send({ - message: "Failed! Username is already in use!" - }); - return; - } - - // Email - User.findOne({ - where: { - email: req.body.email - } - }).then(user => { - if (user) { - res.status(400).send({ - message: "Failed! Email is already in use!" - }); - return; - } - - next(); - }); - }); -}; - -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: checkDuplicateUsernameOrEmail, - checkRolesExisted: checkRolesExisted -}; - -module.exports = verifySignUp; diff --git a/app/models/index.js b/app/models/index.js deleted file mode 100644 index f57f9e9..0000000 --- a/app/models/index.js +++ /dev/null @@ -1,37 +0,0 @@ -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; diff --git a/app/models/role.model.js b/app/models/role.model.js deleted file mode 100644 index 345c247..0000000 --- a/app/models/role.model.js +++ /dev/null @@ -1,13 +0,0 @@ -module.exports = (sequelize, Sequelize) => { - const Role = sequelize.define("roles", { - id: { - type: Sequelize.INTEGER, - primaryKey: true - }, - name: { - type: Sequelize.STRING - } - }); - - return Role; -}; diff --git a/app/models/user.model.js b/app/models/user.model.js deleted file mode 100644 index 63b8c28..0000000 --- a/app/models/user.model.js +++ /dev/null @@ -1,15 +0,0 @@ -module.exports = (sequelize, Sequelize) => { - const User = sequelize.define("users", { - username: { - type: Sequelize.STRING - }, - email: { - type: Sequelize.STRING - }, - password: { - type: Sequelize.STRING - } - }); - - return User; -}; diff --git a/app/routes/auth.routes.js b/app/routes/auth.routes.js deleted file mode 100644 index a4fcd91..0000000 --- a/app/routes/auth.routes.js +++ /dev/null @@ -1,23 +0,0 @@ -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", - "x-access-token, Origin, Content-Type, Accept" - ); - next(); - }); - - app.post( - "/api/auth/signup", - [ - verifySignUp.checkDuplicateUsernameOrEmail, - verifySignUp.checkRolesExisted - ], - controller.signup - ); - - app.post("/api/auth/signin", controller.signin); -}; diff --git a/app/routes/user.routes.js b/app/routes/user.routes.js deleted file mode 100644 index 10f00c5..0000000 --- a/app/routes/user.routes.js +++ /dev/null @@ -1,32 +0,0 @@ -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", - "x-access-token, 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 - ); -}; diff --git a/jwt-refresh-token-node-js-example-flow.png b/jwt-refresh-token-node-js-example-flow.png deleted file mode 100644 index 6db0461..0000000 Binary files a/jwt-refresh-token-node-js-example-flow.png and /dev/null differ diff --git a/jwt-token-authentication-node-js-example-flow.png b/jwt-token-authentication-node-js-example-flow.png deleted file mode 100644 index 8c4efed..0000000 Binary files a/jwt-token-authentication-node-js-example-flow.png and /dev/null differ diff --git a/package.json b/package.json deleted file mode 100644 index 42ff21f..0000000 --- a/package.json +++ /dev/null @@ -1,27 +0,0 @@ -{ - "name": "node-js-jwt-auth-postgresql", - "version": "1.0.0", - "description": "Node.js Demo for JWT Authentication with PostgreSQL", - "main": "server.js", - "scripts": { - "test": "echo \"Error: no test specified\" && exit 1" - }, - "keywords": [ - "node js", - "express", - "jwt", - "authentication", - "postgresql" - ], - "author": "bezkoder", - "license": "ISC", - "dependencies": { - "bcryptjs": "^2.4.3", - "cors": "^2.8.5", - "express": "^4.18.2", - "jsonwebtoken": "^9.0.0", - "pg": "^8.11.1", - "pg-hstore": "^2.3.4", - "sequelize": "^6.32.1" - } -} diff --git a/server.js b/server.js deleted file mode 100644 index 71e6e0a..0000000 --- a/server.js +++ /dev/null @@ -1,59 +0,0 @@ -const express = require("express"); -const cors = require("cors"); - -const app = express(); - -var corsOptions = { - origin: "http://localhost:8081" -}; - -app.use(cors(corsOptions)); - -// 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 })); - -// database -const db = require("./app/models"); -const Role = db.role; - -// db.sequelize.sync(); -// force: true will drop the table if it already exists -db.sequelize.sync({force: true}).then(() => { - console.log('Drop and Resync Database with { force: true }'); - initial(); -}); - -// simple route -app.get("/", (req, res) => { - res.json({ message: "Welcome to bezkoder application." }); -}); - -// routes -require('./app/routes/auth.routes')(app); -require('./app/routes/user.routes')(app); - -// set port, listen for requests -const PORT = process.env.PORT || 8080; -app.listen(PORT, () => { - console.log(`Server is running on port ${PORT}.`); -}); - -function initial() { - Role.create({ - id: 1, - name: "user" - }); - - Role.create({ - id: 2, - name: "moderator" - }); - - Role.create({ - id: 3, - name: "admin" - }); -} \ No newline at end of file