31
loading...
This website collects cookies to deliver better user experience
JSON WEB TOKEN
. JWT has three parts separated by dots (.) . JWT will be created with a secret.
Header
: First part denotes the hash of header (header generally consists of algorithm used for hashing and type)Payload
: Second part will have hash of the payload (payload will contain user id and info, this will be decoded when we verify the JWT.Signature
: Third part will contain an hash of (header + '.' + payLoad + secret). This part plays a crucial role in finding whether the user or anyone didn't tamper with the token before sending the request.So, what verifying JWT will do is, it generates the third part of the hash again from the first and second parts of the JWT token sent with the request. If it matches, then we can get the payload.
Even if any payload or data is modified in frontend and sent to backend. JWT verify will fail because third hash going to be different if data is tampered.
The advantage of the JWT is we are storing the user info in token itself. So, it will work across all servers.
Create a new directory and move in to the directory
Now, run:
npm init - y
package.json
filenpm i express jsonwebtoken dotenv bcrypt cors express
To install nodemon
as a dev-dependency
npm i —save-dev nodemon
Now, package.json will look something like this:
{
"name": "jwt-auth-tutorial",
"version": "1.0.0",
"description": "",
"main": "server.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
// added devStart command
"devStart": "nodemon server.js",
"start": "node server.js"
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"bcrypt": "^5.0.1",
"cors": "^2.8.5",
"dotenv": "^10.0.0",
"express": "^4.17.1",
"jsonwebtoken": "^8.5.1"
},
"devDependencies": {
"nodemon": "^2.0.12"
}
}
start
and devStart
commands in your package.json file, if they don't exist..env
in your project folder where we are going to store all our app secrets 🔒APP_PORT
which basically stores the port number on which our server is going to run..env
file should look something like this
APP_PORT=3000
index.js
file. ( Create the file, if it doesn't exist)
// index.js
var express = require('express');
require('dotenv').config() // will config the .env file present in the directory
const PORT = process.env.APP_PORT || "8081";
const app = express();
app.get('/', (req, res) => {
res.send("Hello !")
})
app.listen(PORT, () => {
console.log("Listening on port", PORT);
})
Postman
// index.js
var express = require('express');
require('dotenv').config() // will config the .env file present in the directory
const db = [
{
username: "Harsha",
password: "hello123"
},
{
username: "Sam",
password: "hello12345"
},
]
const POSTS = [
{
name: "Harsha",
title: "Post 1",
body: "1234"
},
{
name: "Sam",
title: "Post 2",
body: "1234"
},
]
const PORT = process.env.APP_PORT || "8081";
const app = express();
app.get('/', (req, res) => {
res.send("Hello !")
})
app.get("/posts", (req, res) => {
res.status(200).json(POSTS);
})
app.listen(PORT, () => {
console.log("Listening on port", PORT);
})
jwt.signin(user_info, secret, {expiresIn})
method, we'll pass in user info object and a secret and expires in time, if you want to expire the token..env
file as ACCESS_TOKEN_SECRET
and REFRESH_TOKEN_SECRET
var express = require('express');
var bcrypt = require('bcrypt');
var jwt = require('jsonwebtoken');
require('dotenv').config()// will config the .env file present in the directory
let POSTS = [
{
username: "Harsha",
title: "Post 1",
body: "1234"
},
{
username: "Harsha",
title: "Post 2",
body: "1234"
},
{
username: "Harsha",
title: "Post 2",
body: "1234"
},
{
username: "Sm",
title: "Post 2",
body: "1234"
},
{
username: "no",
title: "Post 2",
body: "1234"
},
]
let DB = []
// used to store refresh tokens, as we will manually expire them
let SESSIONS = []
const generateAccessToken = (user) => {
// jwt will make sure to expire this token in 1 hour
return jwt.sign(user, process.env.ACCESS_TOKEN_SECRET, {
'expiresIn': '1h'
})
}
const PORT = process.env.APP_PORT || "8081";
const app = express();
app.use(express.json())
// middlewares
const validateToken = async (token, tokenSecret) => {
// returns user info, if the jwt token is valid
return await jwt.verify(token, tokenSecret,
(error, payload) => {
if (error) {
throw (error)
}
return payload
})
}
const validateAccessToken = async (req, res, next) => {
// returns user info, if the jwt token is valid
try {
req.user = await validateToken(req.body['accessToken'], process.env.ACCESS_TOKEN_SECRET)
next();
}
catch (error) {
res.status(401).
json({ error: error.message || 'Invalid access token' })
}
}
const validateRefreshToken = async (req, res, next) => {
try {
req.user = await validateToken(req.body['refreshToken'], process.env.REFRESH_TOKEN_SECRET)
next();
}
catch (error) {
res.status(401).
json({ error: error.message || 'Invalid refresh token' })
}
}
app.get("/posts", validateAccessToken, (req, res) => {
const { username } = req.user;
const userPosts = POSTS.filter((post) => post.username === username)
res.json(userPosts)
})
app.post("/register", async (req, res) => {
const { username, password } = req.body;
let hash = "";
const salt = await bcrypt.genSalt(12);
hash = await bcrypt.hash(password, salt);
DB.push({ username, passwordHash: hash })
console.log(DB);
res.json("Successfully registered")
})
app.post("/login", async (req, res) => {
const { username, password } = req.body;
for (let user of DB) {
// authentication - checking if password is correct
if (user.username === username && await bcrypt.compare(password, user.passwordHash)) {
const accessToken = jwt.sign({ username: user.username }, process.env.ACCESS_TOKEN_SECRET, {
'expiresIn': '1h'
})
// In this implementation, refresh token doesn't have any expiration date and it will be used to generate new access token
const refreshToken = jwt.sign({ username: user.username }, process.env.REFRESH_TOKEN_SECRET)
// We will store refresh token in db and it'll expire when the user logs out
SESSIONS.push(refreshToken);
// sending accesstoken and refresh token in response
res.json({ accessToken, refreshToken });
}
}
})
app.post('/token', validateRefreshToken, (req, res) => {
// generating new access token, once the refresh token is valid and exists in db
const { username } = req.user;
if (SESSIONS.includes(req.body['refreshToken'])) {
res.json({ accessToken: generateAccessToken({ username })})
}
else {
res.status(403).json('Forbidden: refresh token is expired')
}
})
app.delete("/logout", async (req, res) => {
// deleting refresh token from db
SESSIONS = SESSIONS.filter((session) => session != req.body['refreshToken']);
res.sendStatus(204);
})
app.get('/', (req, res) => {
res.send("Hello !")
})
app.listen(PORT, () => {
console.log("Listening on port", PORT);
})