Have you ever wanted to authenticate and authorize your users on your website? and you don't know-how. this can affect your web app as everyone is concerned about their privacy. There are several ways to handle authentication, we can rely on third-party services like Passport. But in this article, we will use a very simple & self-developed approach, which will help us to understand the core part of the authentication.
Requirements
Nodejs
database: PostgreSQL or other you know
Technology Used
Database: PostgreSQL
Password Hash: bcrypt
Token: JWT(jsonwebtoken)
Multer for uploading photos
Cloudinary for storing user photo
*npm(node package manager) to install
*
npm i bcrypt cloudinary jsonwebtoken multer pg
Basic Structure
First, make your basic express server.
const express = require("express");
const app = express();
const PORT = process.env.PORT || 5000
app.use(express.json());
router.get("/", async (req, res) => {
res.send("hello")
});
app.listen(PORT, ()=>{
console.log(`server started ${PORT}`)
})
Registration / Signup
First, make a file named register.js in your directory it should look like this.
const express = require("express");
const router = express.Router();
const bcrypt = require("bcrypt");
const pool = require("./db"); // database connection
const jwtGenerator = require("./jwtGenerator");
// make a file named multer.js in your directory
const upload = require('./multer')
// make a file named cloudinary to keep your credentials
const cloudinary = require('./cloudinary');
router.post("/register",upload, async (req, res) => {
try {
const { email, name, password } = req.body;
const result = await cloudinary.uploader.upload(req.file.path);
const photo =result.url
// it checks if the email is used or not
const user = await pool.query("SELECT * FROM users WHERE user_email = $1", [
email
]);
if (user.rows.length > 0) {
return res.status(401).json("User already exist!");
}
const salt = await bcrypt.genSalt(10);
const bcryptPassword = await bcrypt.hash(password, salt);
let newUser = await pool.query(
"INSERT INTO users (user_name,user_photo, user_email, user_password) VALUES ($1, $2, $3,$4, $5) RETURNING *",
[name, photo, email, bcryptPassword]
);
const jwtToken = jwtGenerator(newUser.rows[0].user_id);
return res.status(200).json({ jwtToken });
} catch (err) {
console.error(err.message);
res.status(500).send("Server error");
}
});
module.exports = router;
Login
const express = require("express");
const router = express.Router();
const bcrypt = require("bcrypt");
const pool = require("./db");
const jwtGenerator = require("./jwtGenerator");
router.post("/login", async (req, res) => {
const { email, password } = req.body;
try {
const user = await pool.query("SELECT * FROM users WHERE user_email = $1", [
email
]);
if (user.rows.length === 0) {
return res.status(401).json("Invalid Credential");
}
const validPassword = await bcrypt.compare(
password,
user.rows[0].user_password
);
if (!validPassword) {
return res.status(401).json("Invalid Credential");
}
const jwtToken = jwtGenerator(user.rows[0].user_id);
return res.json({ jwtToken });
} catch (err) {
console.error(err.message);
res.status(500).json("Server error");
}
});
module.exports = router;
Verify
You can put it anywhere you want for example login.js or residter.js
// the file must be required in order to verify the user
const authorize = require("./authorize");
router.post("/verify", authorize, (req, res) => {
try {
res.json(true);
} catch (err) {
console.error(err.message);
res.status(500).json("Server error");
}
});
jwtGenerator file
this file must exist in order to generate the token it should look like this.
const jwt = require("jsonwebtoken");
function jwtGenerator(user_id) {
const payload = {
user: {
id: user_id
}
};
return jwt.sign(payload, yourJwtSecret, { expiresIn: "2h" });
}
module.exports = jwtGenerator;
multer file
const multer = require('multer');
const path = require('path')
const storage = multer.diskStorage({
destination: function (req, file, cb) {
cb(null, './uploads/')
},
filename: function (req, file, cb) {
cb(null, Date.now() + file.originalname)
}
})
const upload = multer({
storage: storage,
limits:{fileSize: 100000000000},
fileFilter: function(req, file, cb){
checkFileType(file, cb);
}
}).single('photo')
function checkFileType(file, cb){
// Allowed ext
const filetypes = /jpeg|jpg|png|gif/;
// Check ext
const extname = filetypes.test(path.extname(file.originalname).toLowerCase());
// Check mime
const mimetype = filetypes.test(file.mimetype);
if(mimetype && extname){
return cb(null,true);
} else {
cb({message: 'Error: Images Only!'}, false);
}
}
module.exports= upload;
cloudinary file
In this file, your will need to register in cloudinary the URL:https://cloudinary.com/users/register/free
After doing so go to dashboard and copy and paste your credentials it will be like this
require('dotenv').config();
const cloudinary = require('cloudinary').v2;
cloudinary.config({
cloud_name: //CLOUDINARY_NAME,
api_key: //CLOUDINARY_API_KEY,
api_secret: //CLOUDINARY_API_SECRET,
});
module.exports = cloudinary ;
authorize file
const jwt = require("jsonwebtoken");
require('dotenv').config();
//this middleware will on continue on if the token is inside the local storage
module.exports = function(req, res, next) {
// Get token from header
const token = req.header("jwt_token");
// Check if not token
if (!token) {
return res.status(403).json({ msg: "authorization denied" });
}
// Verify token
try {
//it is going to give use the user id (user:{id: user.id})
const verify = jwt.verify(token, //jwtSecret);
req.user = verify.user;
next();
} catch (err) {
res.status(401).json({ msg: "Token is not valid" });
}
}
db file
const Pool = require("pg").Pool;
const pool = new Pool({
host: "localhost",
user: "postgres",
password: "//your password",
port: 5432,
database: "//name of your database"
});
module.exports = pool;
Now in server or main file should look like this
const express = require("express");
const app = express();
const pool = require("./db");
const authorize = require("./authorize");
const PORT = process.env.PORT || 5000
app.use(express.json());
app.use(express.urlencoded({extended: false}))
app.use('/uploads', express.static('uploads'))
app.use("/", require("./routes/register"));
app.use("/", require("./login"));
router.get("/", async (req, res) => {
res.send("hello")
});
router.get("/profile", authorize, async (req, res) => {
try {
const user = await pool.query(
"SELECT * FROM user WHERE user_id = $1",
[req.user.id]
);
res.json(user.rows);
} catch (err) {
console.error(err.message);
res.status(500).send("Server error");
}
});
app.listen(PORT, ()=>{
console.log(`server started ${PORT}`)
})
Important folder
- uploads folder(should make it so, that multer can access it)
Additional
for database
CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
CREATE TABLE users(
user_id UUID DEFAULT uuid_generate_v4(),
user_photo VARCHAR(255) NOT NULL,
user_name VARCHAR(255) NOT NULL,
user_email VARCHAR(255) NOT NULL UNIQUE,
user_password VARCHAR(255) NOT NULL,
PRIMARY KEY (user_id)
);
As a conclusion you can take this further, and it was written to help people out there who have no clue or have but have never tried and take this article as personal experience and I am not an expert but there are millions of ways to make this work if you face any problem, please tell me I will be happy to help you. you can contact me on my email: brunoblaise94@gmail.com and if it is scary to you and you do not where to start, please let me know if you need a version of this article in a video and I post here mainly pern (PostgreSQL(database), expressjs(server-side), reactjs(client/frontend), nodejs(backend) staffs and errors during the deployment every two weeks. I have a nice day.
Top comments (0)