Wrapping passport.authenticate *callback* inside a function doesn't work - passport.js

This is closely related to Wrapping passport.authenticate inside a function doesn't work.
We are using Koa instead of Express. Hence I replaced the (req, res, next) by (ctx, next). It worked fine for the initial oauth2 call, but the callback throws an error if wrapped in a function.
Works:
router.get('/auth/google/callback', passport.authenticate('google',
{
successRedirect: '/auth/success',
failureRedirect: '/auth/fail',
failureFlash: true,
}));
Fails:
const google_callback = (ctx, next) => {
passport.authenticate('google',
{
successRedirect: '/auth/success',
failureRedirect: '/auth/fail',
failureFlash: true,
}
)(ctx, next);
};
router.get('/auth/google/callback', google_callback);
The error message is:
Error: Can't set headers after they are sent.

This pointed me in the right direction.
Works:
const google_callback = async (ctx, next) => {
await passport.authenticate('google',
{
successRedirect: '/auth/success',
failureRedirect: '/auth/fail',
failureFlash: true,
}
)(ctx, next);
};

Related

How to perform a function before a redirect with passport.authenticate

I am using WebDevSimplifieds version of a login script. So far its working but I am stuck at the moment with a function I would like to to run before it redirects after logging in.
The user is on a login page where he puts in all credentials and if everything is correct, the user will be redirected to index.ejs(html). Before redirecting I would like to run a function which alters a server variable based on what the user put in into a specific field.
This is working, but of course there is no additional function.
app.post(
'/login',
checkNotAuthenticated,
passport.authenticate('local',
{
successRedirect: '/',
failureRedirect: '/login',
failureFlash: true,
}
)
)
I would like to have something like that. The console.log command works, but the passport.authenticate not.
app.post(
'/login',
checkNotAuthenticated, (req, res) => {
console.log("that works");
passport.authenticate('local',
{
successRedirect: '/',
failureRedirect: '/login',
failureFlash: true,
}
)}
)
passport.authenticate returns a function that has the signature (req, res, next), i.e. a middleware.
Compare the source code:
module.exports = function authenticate(passport, name, options, callback) {
// ...
return function authenticate(req, res, next) {
// ...
};
// ...
};
You need to call that function.
app.post(
'/login',
checkNotAuthenticated,
(req, res, next) => {
console.log("that works");
const authFunc = passport.authenticate('local', {
successRedirect: '/',
failureRedirect: '/login',
failureFlash: true,
});
authFunc(req, res, next);
)}
)

Pass req.user.username as a parameter to successRedirect in Passport.js

When a user logs in successfully, I want to redirect them to a route that takes their username as a parameter:
router.post("/login", checkNotAuthenticated, passport.authenticate("local", {
successRedirect: "/dashboard/" + req.user.username,
failureRedirect: "/login",
failureFlash: true,
})
);
router.get("/dashboard/:username", checkAuthenticated, (req, res) => {
res.render("dashboard", { user: req.user });
});
When I try this, I get the following error:
successRedirect: "/dashboard/" + req.user.username,
^
ReferenceError: req is not defined
(I understand why req is not defined, but I am showing this to illustrate what it is I want to do.)
I have tested around with changing the route to the following:
router.post("/login", (req, res) => {
console.log(req.body.username); // a test; prints what is expected
passport.authenticate("local", {
successRedirect: "/dashboard/" + req.body.username,
failureRedirect: "/login",
failureFlash: true,
});
});
When I login with the details, console.log(...) works as expected and prints the user's name. However, the successRedirect does not works as it just keeps loading. There's no form of output in the console, either.
I then also tried req.user.username (in the most recent route), but it just prints:
TypeError: Cannot read property 'username' of undefined
To finally add, when I console.log(req.body), I get:
[Object: null prototype] { username: 'user1', password: 'user1' }
Is there something I am not understanding?
I found a solution (pretty quickly after writing this post). I think it's worth noting, still, in case others are in this position.
router.post(
"/login",
passport.authenticate("local", {
failureRedirect: "/login",
failureFlash: true,
}),(req, res) {
res.redirect("/dashboard/" + req.user.username);
}
);
I ommitted successRedirect, as a successful login will run the route function anyway; all you have to do is account for the failed login attempts (i.e. failureRedirect, or handle a 401 status code), as you can redirect the user with the req.user now existing.
I'm quoting documentation here:
app.post('/login',
passport.authenticate('local'),
function(req, res) {
// If this function gets called, authentication was successful.
// `req.user` contains the authenticated user.
res.redirect('/users/' + req.user.username);
});
passport.authenticate('local') is acting as a middleware and will call the next function that can access the Req object.

Passport Authentication and login redirection

I have two types of user: Admin and Tester.
What I am trying to do: If the user that logs in is an Admin, render 'dashboardA'. If not, render 'dashboard'.
I don't know how to do this and attempted and failed. Below is my code. I'm a novice
Present code
This works fine but it does not differentiate between the userType. I am using handlebars as template engine
const User = require('../models/User');
// Login Handle
router.post('/login', (req, res, next) => {
passport.authenticate('local', {
successRedirect: '/dashboard',
failureRedirect: '/auth/login',
failureFlash: true
})(req, res, next);
});
This is my failed attempt
// Login Handle
router.post('/login', (req, res, next) => {
passport.authenticate('local', { if(User.userType === 'Admin') {
successRedirect: 'dashboardA',
failureRedirect: '/auth/login',
failureFlash: true
} else {
successRedirect: 'dashboard',
failureRedirect: '/auth/login',
failureFlash: true
}
})(req, res, next);
});
Does any one have ideas on how to successfully go about this?
Thanks in advance!

Passport.authenticate successRedirect condition after Google OAuth 2.0 identification

I use this Callback route after Google OAuth 2.0 identification
// Original version working:
// Callback route
router.get( '/google/callback',
passport.authenticate( 'google', {
failureRedirect: '/',
successRedirect: '/dashboard',
}));
I want to redirect the general users to '/dashboard/ but the admin (With email like admin#admin.com ) to '/admin'
I'm trying something like this:
// Callback route
router.get( '/google/callback',
passport.authenticate( 'google', {
failureRedirect: '/',
{
if (req.user.mail === 'admin#admin.com') {
return successRedirect: '/admin';
} else
{
return successRedirect: '/dashboard';
}
}
}));
But I donĀ“t know how to insert the (req, res) after the failureRedirect: '/', line
Also the "return" is needed?
Any help?
Why not use a custom callback as prescribed by the package here.
Implementation:
router.get('/google/callback', (req, res, next) =>
passport.authenticate('google', (err, user, info) => {
if (err) return next(err);
if (!user) return res.redirect('/login');
req.logIn(user, err => {
if (err) return next(err);
if (user.mail === 'admin#admin.com') return res.redirect('/admin');
return res.redirect('/dashboard');
});
})(req, res, next)
);

Passport authenticate, need basic explanation

Can someone explain what is and why do we include (req, res, next), at the end of the passport.authenticate, all I've seen so far in tutorials is that we need it because we want it to fire off immediately, but I don't really understand it.
Here is the code:
router.post('/login', (req, res, next) => { <br>
passport.authenticate('local', { <br>
successRedirect: '/songs/list', <br>
failureRedirect: '/users/login', <br>
failureFlash: true <br>
})(req, res, next); <---- *This line*
You are declaring a function and calling it immediately..You do this so you can access the req object inside the passport.authenticate.
So if you need to access the request object inside the passport you need a custom callback.Your code seems not to use the req object, so you simple use
app.post("/protected",passport.authenticate("local",{
successRedirect:"/user",
failureRedirect:"/login"
}),function(req,res){
});
And if you application need access to req object then :
app.get('/protected', function(req, res, next) {
passport.authenticate('local', function(err, user, profile) {
if (err) { return next(err) }
if (!user) { return res.redirect('/signin') }
res.redirect('/account');
})(req, res, next);
});
More info # https://github.com/jaredhanson/passport/issues/1

Resources