Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: added refresh token #109

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion login-system/dbServer.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ const path = require('path')
const { upload, save, disp } = require(path.resolve(__dirname, '../file_upload/upload.js'));
const {stk_signup,stk_signin}=require('../stakeholder/login')
const {info,check} = require('../file_upload/form_db')
const { signup, signin } = require('./login');
const { signup, signin, refreshAccessToken} = require('./login');
const rateLimiter=require('express-rate-limit')
const { approve,uploadedpapers,displaydetail }= require('../stakeholder/stk_approval')
const {display}=require('../backend/profile');
Expand Down Expand Up @@ -99,6 +99,9 @@ app.post("/login",signin)
app.post("/stk_holder_signin",stk_signin)
app.post('/fac_login',fac_login) //login for faculty

// refresh token
app.post("/refresh",refreshAccessToken)

// approval by stakeholder
app.get('/approval',approve)

Expand Down
183 changes: 96 additions & 87 deletions login-system/login.js
Original file line number Diff line number Diff line change
@@ -1,124 +1,133 @@
const mysql = require('mysql')
const bcrypt = require('bcrypt')
const {generateAccessToken}=require('./token');
const mysql = require('mysql');
const bcrypt = require('bcrypt');
const { generateAccessToken, generateRefreshToken, decodeRefreshToken } = require('./token');
const notify = require('./notification');
const rateLimit = require('express-rate-limit')
require("dotenv").config()
const db = require('../config/mysql_connection')
const rateLimit = require('express-rate-limit');
require("dotenv").config();
const db = require('../config/mysql_connection');


// connecting database to the server
// Connecting database to the server
db.getConnection((err, connection) => {
if (err) throw err;
console.log("Database Connected Successfully")
})
console.log("Database Connected Successfully");
});

// Validate password strength
const validatePassword = (password) => {
const RegexPassword = /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]{7,}$/;
return RegexPassword.test(password)
}
return RegexPassword.test(password);
};

// Rate limiting for signup
const signupRateLimiter = rateLimit({
windowMs : 60*60*1000, // 1 hr
max : 10, // max 10 attempts
message : "Too many signup attempts , please try again after an hour."
})
windowMs: 60 * 60 * 1000, // 1 hour
max: 10, // max 10 attempts
message: "Too many signup attempts, please try again after an hour."
});

// Rate limiting for signin
const signinRateLimiter = rateLimit({
windowMs : 60*60*1000,
max : 15, // max 15 attempts
message : "Too many login attempts, please try again after an hour."
})
windowMs: 60 * 60 * 1000, // 1 hour
max: 15, // max 15 attempts
message: "Too many login attempts, please try again after an hour."
});

const signup=async (req, res) => {
const username = req.body.name.trim()
const email = req.body.email.trim().toLowerCase()
const password = req.body.password.trim()
// Signup function
const signup = async (req, res) => {
const username = req.body.name.trim();
const email = req.body.email.trim().toLowerCase();
const password = req.body.password.trim();

if(!validatePassword(password)){
if (!validatePassword(password)) {
return res.status(400).json({
error : "Password Invalid ... Password must be atleast 7 character long and must contain atleast 1 uppercase & lowercase character , 1 number and 1 special character"
})
error: "Password Invalid ... Password must be at least 7 characters long and must contain at least 1 uppercase & lowercase character, 1 number, and 1 special character."
});
}

const hashpassword = await bcrypt.hash(req.body.password, 10);

db.getConnection(async (err, connection) => {
if (err) throw (err)
const sqlSearch = "SELECT * FROM user_table WHERE email=? OR username=?";
const search_query = mysql.format(sqlSearch, [email,username])

const sqlinsert = "INSERT INTO user_table VALUES (0,?,?,?)"
const insert_query = mysql.format(sqlinsert, [username, email, hashpassword])
if (err) throw (err);
const sqlSearch = "SELECT * FROM user_table WHERE email=? OR username=?";
const search_query = mysql.format(sqlSearch, [email, username]);

const sqlInsert = "INSERT INTO user_table VALUES (0,?,?,?)";
const insert_query = mysql.format(sqlInsert, [username, email, hashpassword]);

await connection.query(search_query, async (err, result) => {
if (err) throw (err)
console.log("search results",result.length)
if (err) throw (err);
console.log("search results", result.length);
if (result.length != 0) {
connection.release()

if(result[0].email === email){
console.log("A User with Entered Email already exists")
res.status(404).send(
"Email Already in Use"
)
}else if(result[0].username === username){
console.log("A User with Entered Username already exists")
res.status(404).send(
"Username Already in Use"
)
connection.release();

if (result[0].email === email) {
console.log("A User with Entered Email already exists");
res.status(404).send("Email Already in Use");
} else if (result[0].username === username) {
console.log("A User with Entered Username already exists");
res.status(404).send("Username Already in Use");
}
}
else {
} else {
await connection.query(insert_query, async (err, result) => {
connection.release();
if (err) throw (err)
console.log("Created a new User")
const sub='Signup-Research Nexas '
// const content=`Account created successfully with username ${result[0].username} in Research Nexas`
// notify(req,res,result[0].email,sub,content);
if (err) throw (err);
console.log("Created a new User");
const sub = 'Signup-Research Nexas';
// const content = `Account created successfully with username ${result[0].username} in Research Nexas`;
// notify(req, res, result[0].email, sub, content);
res.sendStatus(201);
})
});
}
})
})
});
});
}

// login backend
const signin=(req, res) => {
const email = req.body.email.trim()
// Signin function
const signin = async (req, res) => {
const email = req.body.email.trim();
const password = req.body.password.trim();
db.getConnection(async (err, connection) => {
if (err) throw (err)
const sqlSearch = "Select * from user_table where email=?"
const search_query = mysql.format(sqlSearch, [email])
if (err) throw (err);
const sqlSearch = "SELECT * FROM user_table WHERE email=?";
const search_query = mysql.format(sqlSearch, [email]);
await connection.query(search_query, async (err, result) => {
if (err) throw (err)
if (err) throw (err);
if (result.length == 0) {
console.log("User does not exist")
res.sendStatus(404)
}
else {
const hashpassword = result[0].password
console.log("User does not exist");
return res.sendStatus(404);
} else {
const hashpassword = result[0].password;
if (await bcrypt.compare(password, hashpassword)) {
console.log("Login Successful")
const token = generateAccessToken({ user: result[0].userid });
console.log(token)
res.json({ accessToken: token })
const sub='Log in-Research Nexas '
// const content=`Login successfully to the account with username ${result[0].username}`
// notify(req,res,result[0].email,sub,content);
}
else {
res.status(401).send("password incorrect")
console.log("Login Successful");
const accessToken = generateAccessToken({ user: result[0].userid });
const refreshToken = generateRefreshToken({ user: result[0].userid }); // Generate refresh token
console.log(accessToken, refreshToken);
res.json({ accessToken, refreshToken }); // Send both tokens
} else {
res.status(401).send("Password incorrect");
}
}
connection.release()
})
})
connection.release();
});
});
}

// Refresh token function
const refreshAccessToken = (req, res) => {
const refreshToken = req.body.refreshToken; // Assume the refresh token is sent in the request body
if (!refreshToken) return res.sendStatus(401); // Unauthorized if refresh token is not present

const decoded = decodeRefreshToken(refreshToken);
if (!decoded) return res.sendStatus(403); // Forbidden if refresh token is invalid

// Generate new access token
const newAccessToken = generateAccessToken({ user: decoded.user });
res.json({ accessToken: newAccessToken });
}

// exporting signup,signin funtion
module.exports={
signup : [signupRateLimiter,signup],
signin : [signinRateLimiter,signin]
}
// Exporting signup, signin, refresh token, and logout functions
module.exports = {
signup: [signupRateLimiter, signup],
signin: [signinRateLimiter, signin],
refreshAccessToken,
};
112 changes: 70 additions & 42 deletions login-system/token.js
Original file line number Diff line number Diff line change
@@ -1,55 +1,83 @@
require("dotenv").config()
const jwt = require("jsonwebtoken")
const crypto=require('crypto');
const ACCESS_TOKEN = process.env.ACCESS_TOKEN_SECRET

// check for valid access token
if(!ACCESS_TOKEN){
throw new Error("Missing ACCESS_TOKEN_SECRET in environment variables.");
require("dotenv").config();
const jwt = require("jsonwebtoken");
const crypto = require('crypto');
const ACCESS_TOKEN = process.env.ACCESS_TOKEN_SECRET;
const REFRESH_TOKEN = process.env.REFRESH_TOKEN_SECRET; // Add this line

// Check for valid secrets
if (!ACCESS_TOKEN || !REFRESH_TOKEN) {
throw new Error("Missing ACCESS_TOKEN_SECRET or REFRESH_TOKEN_SECRET in environment variables.");
}
// function for generating access token
function generateAccessToken(user,expireTime = "20m") {
try{
const token = jwt.sign(user,ACCESS_TOKEN,{expiresIn : expireTime});
return token;
}catch(err){

// Function for generating access token
function generateAccessToken(user, expireTime = "20m") {
try {
const token = jwt.sign(user, ACCESS_TOKEN, { expiresIn: expireTime });
return token;
} catch (err) {
console.log({
Message : "Error While Generating The Token",
Error : err.message
})
Message: "Error While Generating The Access Token",
Error: err.message
});
return null;
}
}
}

// function for decoding the token
function decodeAccessToken(AuthHeader){
if(!AuthHeader){
console.log("Authorization header is missing");
return null;
}

const token = AuthHeader.split(" ")[1];
if(!token){
console.log("Token is missing");
return null;
}
try{

const decodedToken = jwt.verify(token,ACCESS_TOKEN)
// Function for generating refresh token
function generateRefreshToken(user) {
try {
const token = jwt.sign(user, REFRESH_TOKEN, { expiresIn: "7d" }); // Valid for 7 days
return token;
} catch (err) {
console.log({
Message: "Error While Generating The Refresh Token",
Error: err.message
});
return null;
}
}

// Function for decoding the token
function decodeAccessToken(AuthHeader) {
if (!AuthHeader) {
console.log("Authorization header is missing");
return null;
}

const token = AuthHeader.split(" ")[1];
if (!token) {
console.log("Token is missing");
return null;
}
try {
const decodedToken = jwt.verify(token, ACCESS_TOKEN);
return decodedToken;
} catch (err) {
console.log({
Message: "Error decoding access token:",
Error: err.message
});
return null;
}
}

// Function for decoding the refresh token
function decodeRefreshToken(token) {
try {
const decodedToken = jwt.verify(token, REFRESH_TOKEN);
return decodedToken;

}catch(err){
} catch (err) {
console.log({
Message : "Error decoding access token:",
Error : err.message
})
return null
Message: "Error decoding refresh token:",
Error: err.message
});
return null;
}
}

// generating registration token for faculties
// Generating registration token for faculties
function registrationToken(email) {
return crypto.createHash('sha256').update(email).digest('hex');
}
}

module.exports={ generateAccessToken, decodeAccessToken ,registrationToken}
module.exports = { generateAccessToken, decodeAccessToken, generateRefreshToken, decodeRefreshToken, registrationToken };