Following the The Complete 2023 Web Development Bootcamp-course by the App Brewery on Udemy, having progressed to lesson 386: Using Passport.js to Add Cookies and Sessions, I am wondering what the purpose is of (req, res, function() {...}) immediately after passport.authenticate('local') for registering a new user using passport-local-mongoose.
Source where the teacher has it from: https://mherman.org/blog/user-authentication-with-passport-dot-js/
(referenced in the documentation for passport-local-mongoose)
In context from the above link:
app.post('/register', function(req, res) {
Account.register(new Account({ username : req.body.username }), req.body.password, function(err, account) {
if (err) {
return res.render('register', { account : account });
}
passport.authenticate('local')(req, res, function () {
res.redirect('/');
});
});
});
Why isn't it written as:
...
passport.authenticate('local', function(req, res) {
res.redirect('/');
});
...
with the callback included as an argument?
Trying approaches that adhere to what I've become familiar with thus far, found in the Passport.js documentation and the passport-local-mongoose documentation, the user gets registered, but the redirection to the secrets-page is not done, instead having the page's load-indicator run continuously without changing from the register-page.
The route for reference below.
app.route("/register").get(function (req, res) {
res.render("register");
}).post(function (req, res) {
User.register({username: req.body.username}, req.body.password, function (err, user) {
if (err) {
console.log(err);
res.redirect("/register");
}
//WORKS: The App Brewery
//Based on: https://mherman.org/blog/user-authentication-with-passport-dot-js/#add-registerjade, 2022-12-25
passport.authenticate("local")(req, res, function () {
res.redirect("/secrets");
});
//DOESN'T WORK: Passport documentation on authentication
// passport.authenticate(
// "local",
// {failureRedirect: "/", failureMessage: true},
// function (req, res) {
// res.redirect("/secrets");
// });
//DOESN'T WORK: passport-local-mongoose documentation
// const authenticate = User.authenticate();
// authenticate(req.body.username, req.body.password, function (err, result) {
// if (err) {
// console.log(err);
// } else {
// res.redirect("/secrets");
// }
// });
});
});
Related
Im trying to test using postman but i have a passport authentication which is blocking me from testing as it will redirect me to the login screen it is not authenticated.
How i can get a token or authenticate myself in postman to be able to test
I have tried to use /auth/local in postman but it just returns that i cant get the route
Passport.js
var LocalStrategy = require('passport-local').Strategy;
var { User } = require('../model/user.js');
var bcrypt = require('bcrypt');
module.exports = function (passport) {
passport.use(new LocalStrategy(function (username, password, done) {
let query = { username: username };
User.findOne(query, function (err, user) {
if (err) throw err;
if (!user) {
return done(null, false,{ message: 'No user found' });
}
bcrypt.compare(password, user.password, function (err, isMatch) {
if (err) throw err;
if (isMatch) {
return done(null, user);
} else {
return done(null, false,{ message: 'Wrong password' });
}
});
});
}));
passport.serializeUser(function (user, done) {
done(null, user.id);
});
passport.deserializeUser(function (id, done) {
User.findById(id, function (err, user) {
done(err, user);
});
});
}
Route.js
router.get('/register', function (req, res) {
res.sendFile(__dirname + "/views/register.html");
});
router.post('/register', async (req, res) => {
var data = req.body;
var salt = await bcrypt.genSalt(10)
var hashedpw = await bcrypt.hash(data.password, salt)
const newUser = await User.create({
name: data.name,
email: data.email,
username: data.username,
password: hashedpw,
});
newUser.save();
req.flash('success', 'You are now registered and can log in');
res.redirect('/');
});
router.get('/login', function (req, res) {
res.locals.success = req.flash('success');
res.locals.error = req.flash('message');
res.render(__dirname + "/views/login.ejs");
});
router.post('/login', async (req, res, next) => {
passport.authenticate('local', {
successRedirect: '/',
failureRedirect: '/login',
failureFlash: true
})(req, res, next);
});
router.get('/logout', async (req, res) => {
req.logout(function (err) {
if (err) { return next(err); }
req.flash('success', 'You are logged out');
res.redirect("/")
});
});
function ensureAuthenticated(req, res, next) {
if (req.isAuthenticated()) {
return next();
} else {
res.redirect('/login');
}
}
Following this guide:
https://mevelix.com/articles/postman-auth-for-laravel,4
you have to create the Command:
php artisan make:command DevPostman
then in the newly created class, copy the content it is showed in the link,
inside the class namespace App\Console\Commands\DevPostmanCommand
Then you can execute the command:
php artisan dev:postman web
in this way you are creating a simulated session.
This is my ouput, for example:
you paste this output directly in PostMan, inside the Tab Pre-Request Scripts:
In this way you are allowed to avoid the login inside Postman, because you are simulating a session.
See the first link to have the complete code of the DevPostmanCommand class.
app.post("/login", passport.authenticate("local",), function (req, res) {
const user = new Model({
username: req.body.username,
password: req.body.password,
});
req.login(user, function (err) {
if (err) {
console.log("wrong password");
} else {
passport.authenticate("local")(req, res, function () {
res.redirect("/admin");
});
}
});
});
app.post("/admin", function (req, res) {
Model.findOne({username: "siddharth"}).exec(function(err, foundList){
if(foundList)
{
const list = new linkModel({
linkTitle: req.body.linkTitle,
linkUrl: req.body.linkUrl,
});
foundList.links.push(list);
foundList.save();
res.redirect("/admin");
}
else
{res.send("redirect to home page and then login");
res.redirect("/login");
}
});
});
How can i pass the username when authenticated from login routeto other route(admin) where mongoose query is defined findone?
As i have defined it explicitly.
Or i simple terms how can i pass the data among routes ?
You can't. Instead use a middleware to do the checks you want and pass on the result to another middleware or return the response in case of error.
I'm working on a freecodecamp challenge. I'm trying to register a user and login the same user but couldn't do it successfully.
I've tried various methods by changing my code a couple of times but still was not successful.
// Register
app.route('/register').post((req, res, next) => {
db.collection('users').findOne({ username: req.body.username }, function (err, user) {
if(err) {
console.log('error')
next(err);
} else if (user) {
console.log('redirect to home-page')
res.redirect('/');
} else {
db.collection('users').insertOne({username: req.body.username, password: req.body.password}, (err, doc) => {
if(err) {
console.log('error after recored')
res.redirect('/');
} else {
console.log('error with user', doc);
next(null, user);
}
}
)
}
})},
passport.authenticate('local', { failureRedirect: '/' }), (req, res, next) => {
res.redirect('/profile');
});
I have the complete code here for your reference.
I should be able to register and it directs me to my profile.
Login successfully and redirect to the profile.
In the code that you have referenced, you seem to have a typo in the Passport local strategy handler.
passport.use(new LocalStrategy(
function(username, password, done){
db.collection('user').findOne({username: username}, (err, user) => {
The collection here should be users as the Register route creates a entry in the users collection.
I am using passport for my node.js app.
When I want to authenticate users local, I can simply do it
function local(req, res) {
req._passport.instance.authenticate('local', function(err, user, info) {
if(err) {
return workflow.emit('exception', err);
}
// and so on
res.end('some data');
}
}
But when I want to use facebook strategy, I must use redirectUrls like this.
function signinFacebook(req, res, next) {
req._passport.instance.authenticate('facebook')(req, res, next);
}
function facebookCallback(req, res, next) {
req._passport.instance.authenticate('facebook', {
successRedirect: '/',
failureRedirect: '/'
})(req, res, next);
}
This way I cant send with response data, that I am sending on local strategy.
Can anyone help me to fix it. I want not give success and failure Redirects, I want to call some function if all goes well like on local strategy.
I've found this in Passport's documentation, it may help.
app.get('/login', function(req, res, next) {
passport.authenticate('local', function(err, user, info) {
if (err) { return next(err); }
if (!user) { return res.redirect('/login'); }
req.logIn(user, function(err) {
if (err) { return next(err); }
return res.redirect('/users/' + user.username);
});
})(req, res, next);
});
Note that when using a custom callback, it becomes the application's responsibility to establish a session (by calling req.login()) and send a response.
I am using nodejs for a project,now I want login my account with passport npm,but not from webpage,from request post method,can it be done?
main code like this:
router.post('/login',function(req, res, next) {
passport.authenticate('local', function(err, user, info) {
if (err) { return next(err); }
if (!user) { return res.json(null); }
req.logIn(user, function(err) {
if (err) { return next(err); }
//return res.redirect('/'); redirect not work
});
})(req, res, next);
});
router.get('/check',function(req, res, next) {
request.post({
url:'http://localhost/login',
headers:{
'Content-Type': 'application/x-www-form-urlencoded'
},
form:{
username:'myname',
password:'mypassword'
}},function(err,httpRes,body){
//do here...?
return res.redirect('/');
});
});
When I call "check" with get method and use the correct username/password,I can print out the user data from database in "login" method,but lost the user session when it redirect home page.Any suggestion?
It's not redirecting the user when they GET /check because the POST request to /login in /check is getting redirected itself, not the actual user. Also making internal requests to internal webpages isn't the best solution for logging in. I suggest creating login() middleware like so:
// Don't forget to set req.body.username and req.body.password when calling login().
var login = function login(req, res, next) {
passport.authenticate('local', function(err, user, info) {
if (err) { return next(err); }
if (!user) { return next(); }
req.logIn(user, function(err) {
if (err) { return next(err); }
return next(null);
});
})(req, res, next);
};
And then calling it appropriately:
router.post('/login', login, function(req, res, next) {
if (req.user) {
console.log('We logged in successfully!');
res.redirect('/');
} else {
res.json(null);
}
});
router.get('/check', function(req, res, next) {
if (!req.user) {
login(req, res, function(err) {
if (err) {
return next(err);
}
if (!req.user) {
// No user, do some error handling.
} else {
// We have the user, do some custom stuff...
}
res.redirect('/');
});
} else {
// User is logged in already, do some other custom stuff...
}
});
You can check if a user is logged in by checking if req.user exists.