How to Refactor different Passport Strategies to their own files - passport.js

At this point, I have one single file with multiple passport strategies for local and third-party authentication. I am now trying to refactor each Strategy to its own file but that throws a bunch of errors.
I tried this :
passport.use("local-signup", signupStrategy); //in the main file and
const signupStrategy = require('passport-local').Strategy({//function}); //in the other file
But this throws 'authentication strategies must have a name' Error.
How do I fix this?

This is how I abstract strategies into their own files. Also note that the strategy name given in passport.use('local-signup') must match the name in passport.authenticate('local-signup') on the route.
main.js
// Require your strategies
const LocalStrategy = require('passport-local').Strategy;
// Require all the strategy callbacks
const localSignUpStrategy = require('./strategies/localSignup');
// Strategy configurations
passport.use('local-signup', new LocalStrategy(localSignUpStrategy));
localSignup.js
const localSignUpStrategy = async (username, password, done) => {
try {
const { dataValues: user } = await User.findOne({ where: { username } }) || {};
// Send found user ID
return done(null, user);
} catch (err) {
return done(err);
}
};
module.exports = localLoginStrategy;

Related

Unable to get document using document.findOne()

I tried to get a document using document.findOne() but it's value is showing undefined .
Here is my code
`app.post("/studentlogin",(req,res)=>
{
let password;
console.log("login page");
bcrypt.hash(req.body.password,saltRounds,(err,hash)=>
{
const user= Student.findOne({srno:req.body.srno});
console.log(user.srno);
if(req.body.srno==user.srno && hash==user.password)
{
session=req.username;
session.userid=req.body.srno;
res.redirect("/");
}
else{
console.log("invalid user");
res.redirect("/studentlogin");
}
});
})`
I'm implementing session authentication using express-session. Here when I log the user it's showing schema and bunch of other stuff which I don't know(The error is too long) . user.srno is also showing as undefined. How can I fix it?
I tried using call-back function which gave me required document correctly. But I want the query to return the correct document and store it in user.
Using callback function
`app.post("/studentlogin",(req,res)=>
{
let password;
console.log("login page");
bcrypt.hash(req.body.password,saltRounds,(err,hash)=>
{
Student.findOne({srno:req.body.srno},(err,result)=>
{
console.log(result);
});
//console.log(user.srno);
if(req.body.srno==user.srno && hash==user.password)
{
session=req.username;
session.userid=req.body.srno;
res.redirect("/");
}
else{
console.log("invalid user");
res.redirect("/studentlogin");
}
});
})`
You need to wait the result from your query on the database before doing the next task like comparing your password, and looks like you just try to log in, you re not going to register a new one, so it's better to use the compare method in Bcrypt like this :
app.post("/studentlogin", async (req , res) => {
const {srno, password} = req.body // destructuring your request is better for visibility
try {
const user = await Student.findOne({srno: srno});//await the result before next step
console.log(user.srno) //you can check
if(!user) {
console.log("invalid user");
// your logic to tell not student found /wrong username or password, and/or redirect
}
const isMatch = await bcrypt.compare(password, user.password) //await the result and this method for comparing the request password and the user's password found
if(!isMatch) {
//your code to tell Wrong username or password
res.redirect("/studentlogin");
} else {
// your code to access to the login.
res.redirect("/");
}
} catch (err) {
console.log(err)
}
The error you are facing is because you are not using async await in your code. use async in your function definition then use await where you are searching the database.
const someFunction = async(req,res)=>{
// your code
const user=await Student.findOne({srno:req.body.srno});
// your code
}
Your code should look like this.
app.post("/studentlogin", async(req,res)=> {
// your code
const user=await Student.findOne({srno:req.body.srno});
// your code
}
console.log(user) to verify.
Hope it helps.

Passing req.session to route

I'm trying to make login session in nodejs,
My app.js
app.post('/login', async(req, res) => {
const { login, password } = req.body
const admin = await register.findOne({ where: { login } })
if (await bcrypt.compare(password, admin.password)) {
req.session.admin = true
res.render('adminPage', { session:req.session.admin }) <---- this not working
} else {
res.send("Wrong password...")
}
})
I'm trying to pass " req.session.admin" to my route to make some kind of authentication
My routes/adminPage.js
const express = require('express')
const router = express.Router()
router.get('/', (req, res) => {
//request.session.admin always giving me "undefined"
try { if (request.session.admin == true) res.render('adminPage') } catch {
res.send("You have to log in...")
}
})
module.exports = router
Is it possible to do or am I stupid?
If you're just initializing a key called session in you request object then indeed your data is being lost after sending the response. I'd go for a third-party solution which persists and rehydrates the data, manages expiration date, so on... Eg: Express-session
Also, I would move my logic to check "whether the user is logged in" to a middleware so I could reuse that code and have it separeted from the main concern of the endpoint.

How to pass extra data and check if token is valid with JWT

I just started a project where I have to use Node + few things related to it and I feel a little confused!
I use JWT for authentication, particularly I created my project like this:
api
|---teams
|----teams.controller.js
|----teams.router.js
|----teams.service.js
|---users (same as team)
auth
|---token_validation.js
other things
|---other things
I use token_validation.js for JWT to validate user while login and seems it work (verified with Postman)
const jwt = require("jsonwebtoken");
module.exports = {
checkToken: (req, res, next) => {
let token = req.get("authorization");
if (token) {
// Remove Bearer from string
token = token.slice(7);
jwt.verify(token, process.env.JWT_KEY, (err, decoded) => {
if (err) {
console.log("err: " + err);
return res.json({
success: 0,
message: "Invalid Token..."
});
} else {
req.decoded = decoded;
next();
}
});
} else {
// other code
}
}
};
I need to insert a new team in DB (MariaDB) and user can create a new team after login. My problem is that while using Session in Java for e.g. I can easly set extras like username of the logged in user and when I need to know what's the username of the logged in user is, I can take it from session
String username = (String) session.getAttribute("username");
I can't understand how to do the same with Node/JWT. What I need to do is, after login I need to save the user_id and when user crate a new team I need to send to DB the user_id with other data (if token still valid).
const {
create
} = require("./teams.service");
module.exports = {
createTeam: (req, res) => {
const body = req.body;
// here I need to check if token still valid
// if yes -> take user id and send it to DB with
// other data
create(body, (err, results) => {
if (err) { // if fails
// handle
}
return res.status(200).json({ // success
success: 1,
data: results
});
});
},
}
I thought I could add it in user.controller.js when user login:
if (result) {
results.password = undefined;
const jsontoken = sign({ result: results }, process.env.JWT_KEY, {
expiresIn: "1h",
user_id: get somehow //error
});
// other code
}
but it gives me an error, tells me like I can't add user_id to sign. Can anyone please tell me the right way to store and get this kind of data and use them when needed while user still have a valid token to stay logged in?
You are adding your data to the options, not the payload.
if (result) {
results.password = undefined;
results.user_id = XXXXXXXX //get somehow
const jsontoken = sign({ result: results }, process.env.JWT_KEY, {
expiresIn: "1h"
});
...
}
Best option is to set it in localStorage. When you make a req to backend send it with headers, then in backend check if token is valid and send response with data that you want.

How to perform database related code in model

I am .NET developer and learning MEAN stack, developing an API for simple post and comment app. I am using MVC pattern without view as it is API. Here is how I am trying to create my model function :
const User = module.exports = mongoose.model('User',UserSchema);
module.exports.getUsers = function(callback){
User.find()
.exec(function(err,list_users){
if(err) { callback(); }
return list_users;
});
}
And here is the controller :
exports.user_list = function(req,res,next){
User.getUsers((err,list_users) => {
if(err){ next(err);}
res.json({user_list : list_users});
})
}
I am getting an error as getUsers is not getting imported. I am trying here to separate the data access code from controller and make controller only to manage request and response as I have been doing in .NET. Any help how can I achieve this?
I would look through the documentation to get familiar with how to use mongoose.
First thing I see is that you are not defining the methods correctly according to the documentation here http://mongoosejs.com/docs/guide.html#methods.
But you do not have to define a find() function. Mongoose already has it built in.
So the next step would be how are you creating the instance of the Model in your controller.
Your model should be:
const mongoose = require('mongoose'),
UserSchema = mongoose.Schema();
const User = new UserSchema({
// define user
});
module.exports = mongoose.model('User',UserSchema);
And the controller:
const User = require('path_to_User_model');
exports.user_list = function(req,res,next){
User.find((err,result)=>{
if(err)
// log err and send response
else
// send the result ex: res.json(result);
});
}
also read through the setup on the npmjs website. https://www.npmjs.com/package/mongoose
So to create have your data functions and have your controller use that function you may try
const mongoose = require('mongoose'),
UserSchema = mongoose.Schema();
const User = new UserSchema({
// define user
});
// data functions
User.methods.getUsers = function (){
User.find((err,result)=>{
if(err)
// log err and return something
return false;
else
return result;
});
}
module.exports = mongoose.model('User',UserSchema);
then the controller
const User = require('path_to_User_model');
exports.user_list = function(req,res,next){
var users = User.getUsers();
if (!users)
res.status(500).send('error_page');
else
res.json(users);
}

How to properly organize routes in ExpressJS?

I'm developing my first test application on NodeJS and encountered the following problem: i can't figure out how to properly organize routes in ExpressJS framework. For example i want to do registration, so i create route like:
app.get('/registration', function (request, response) {
if (request.body.user.email && request.body.user.password) {
var user = new User();
var result = user.createNew(request.body.user.email, request.body.user.email);
// do stuff...
}
response.render('registration.html', config);
});
User function looks like this (not the final):
function User() {
var userSchema = new mongoose.Schema({
'email': {
'type': String,
'required': true,
'lowercase': true,
'index': { 'unique': true }
},
'password': {
'type': String,
'required': true
}
});
var userModel = mongoose.model('users', userSchema);
this.createNew = function(email, password) {
var new_user = new users({'email': email, 'password': password});
new_user.save(function(err){
console.log('Save function');
if (err)
return false;
return true;
});
}
}
I try to do a bit of structured applications like MVC. The problem is that the save method is asynch and each time i registrate new user get registration.html without waiting for the result.
Basically i need to run route callback in save callback, but how to do this in the right way i can't figure out by myself...
this.createNew = function(email, password, callback) {
var new_user = new users({'email': email, 'password': password});
new_user.save(function(err){
console.log('Save function');
if (err)
// return false;
callback (false);
else
//return true;
callback (true);
});
}
I find that whenever I'm using some module (db for example) and it's using a callback, I will often have to also use a callback for any function I wrap around it (unless I don't care about the results).
Here:
app.get('/registration', function (request, response) {
if (request.body.user.email && request.body.user.password) {
var user = new User();
// var result = user.createNew(request.body.user.email, request.body.user.email);
user.createNew(request.body.user.email, request.body.user.email, function (results) {
// do something with results (will be true or false)
// not sure why you have this with the actual registration stuff,
// but it's your site. :)
response.render('registration.html', config);
});
}
});
Also, you might want to put your object methods in the prototype, instead of:
this.createNew = function (....) {}
Try:
User.prototype.createNew = function ( ... ) { }
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Closures#Performance_considerations for info on why.
For a starting point on organising your Node.js app, try reading through the source code on this demo express.js app. Click here for the link
It's a fairly popular repo, which I often find myself referencing when building Node.js apps from scratch.
It may be a good reference for your project given it's done in an the MVC style and it uses mongoose. The routes are organised into a single file which can be found in config/routes.js. You should also take a look at the models in app/models/ for an alternative way to organise your user model

Resources