I'm having a problem where if I try to login with no username or password my passport.use function isn't being called at all.
Below is my express post route that runs passport.authenticate.
app.post('/login', passport.authenticate('local-login', {
failureRedirect: '/login', // redirect back to the login page if there is an error
failureFlash: true // allow flash messages
})
And below is my passport.use that should print GOT HERE whenever there is a post request to /login.
passport.use('local-login', new LocalStrategy({
// by default, local strategy uses username and password, we will override with email
usernameField: 'email',
passwordField: 'password',
passReqToCallback: true // allows us to pass back the entire request to the callback
},
function(req, email, password, done) { // callback with email and password from our form
// find a user whose email is the same as the forms email
// we are checking to see if the user trying to login already exists
console.log("GOT HERE");
This works fine if email and password have some type of value. But I would like this function to be called even if there is no value for email and password so that I can do custom error handling.
How can I achieve this?
You could add middleware befure authentication strategy being called. Something like this:
app.post('/login', function(req, res, next) {
// do custom error handling
}, passport.authenticate('local-login', {
failureRedirect: '/login', // redirect back to the login page if there is an error
failureFlash: true // allow flash messages
})
And in this middleware you could do some custom error handling
Related
Hello I am new to Passport.js, I am trying to implement the passport authenticate method but I am always having the failureRedirect as a result.
All I want to know is if there is a way to console the error causing this failure or not.
Here is my code:
app.post('/platform/adminsignin', passport.authenticate('platformlocal', {
successRedirect: '/platform/dashboard',
failureRedirect: '/platform/adminlogin',
failureFlash: true,
}), function (req, res, info) {
logger.info('Function should not execute');
});
I am always being redirected to adminlogin, I want to know if there is a way to get the reason of this failure.
Any advice could help, thanks.
I'm a beginner with all things Node and trying to configure a simple passport-local strategy for my app. I was able to create a new user in my database, but beyond that I'm having trouble getting passport.js to work as expected.
Here's my express app structure:
routes
- api
- events.js
- users.js
services
- passport.js
server.js
In server.js I'm configuring the routes individually, like app.use('/api/users', require('./routes/api/users'). Just before that I'm doing the following passport setup:
const session = require('express-session');
const cookieParser = require('cookie-parser');
const passport = require('passport');
const flash = require('connect-flash');
require('./services/passport')(passport);
app.use(session({ secret: process.env.SESSION_SECRET,
resave: true,
saveUninitialized: true }));
app.use(passport.initialize());
app.use(passport.session());
app.use(flash());
My passport.js file looks like this:
const knex = require('../db/knex.js');
const LocalStrategy = require('passport-local').Strategy;
const bcrypt = require('bcryptjs');
const saltRounds = 12;
module.exports = function(passport) {
passport.serializeUser(function(user, done) {
done(null, user);
});
passport.deserializeUser(function(user, done) {
done(null, user);
});
passport.use('local-signup', new LocalStrategy({
// by default, local strategy uses username and password, we will override with email
usernameField: 'email',
passwordField: 'password',
passReqToCallback: true
},
function(req, email, password, done) {
knex('users')
.where({email: email}).first()
.then(function(user) {
if (user) { return done(null, false, {message: 'User with that email already exists!'}) }
else {
bcrypt.hash(password, saltRounds, function(err, hash) {
var newUser = new Object();
newUser.username = req.body.username;
newUser.email = email;
newUser.password = hash;
knex('users')
.insert(newUser)
.then(done(null, newUser))
.catch(err => { return done(err) })
})
}
})
.catch(err => { return done(err) });
}));
};
And then in users.js I have:
const express = require('express');
const router = express.Router();
const knex = require('../../db/knex.js');
const passport = require('passport');
...
router.post('/signup', passport.authenticate('local-signup', {
successRedirect: '/',
failureRedirect: '/',
failureFlash: true
}));
I'll eventually want to make successRedirect and failureRedirect different from each other, of course, but for now I just want to understand how to make them work. As I mentioned, this code successfully inserted a user into the database. But when I try to create another account with the same credentials, nothing happens. The behavior I'd expect is to see the message "User with that email already exists!" and be redirected to my homepage.
Note that my homepage is at http://localhost:3000, so I'm not sure if setting the redirect to '/' points there or to the current page. The current page is http://localhost:3000/auth, which contains a React component with my signup form, making a POST call to /api/users/signup/. So it's conceivable that '/' would actually look for http://localhost:3000/api/users/signup which as of now doesn't have a GET method. But I'm not getting a 404 or anything; nothing happens, and there's no error. Any advice greatly appreciated.
UPDATE
I just confirmed that removing both redirects causes a 401 response as expected. Also, setting the failureRedirect to /events produces a 404, which is odd because http://localhost:3000/events is definitely configured.
EDIT
I realized it might help to show how I'm making the API call on the client side. Pressing a submit button calls the following signup function:
signup(e) {
e.preventDefault();
axios.post('/api/users/signup', {
username: this.state.username,
email: this.state.email,
password: this.state.password
})
.catch(err => console.log(err));
}
Is your express backend just used as a data API? Because if it is then I'm not sure if the PassportJS redirection would work.
I remember using it in a completely server side rendered app, where the routing was completely on backend, that kind of situation makes it work because any routing is handled on backend and it renders the page then sends it to client.
On a react app, the routing (the actual change in page/url) is handled on frontend, so doing it in Passport like this won't work. I think the best you can do is have error handling in passport that sends some kind of status or message to frontend and then handle it on frontend because that's where the routing is.
For those still facing an issue with sessions resetting when using Passport, I spent hours tracing and debugging only to find out that Passport's authenticate() resets the entire request session internally without so much as a warning. The documentation is just awful, but anyway...
The culprit is the SessionManager part of the framework, as can be seen here
// this line below
req.session.regenerate(function(err) { ... });
Passing the option keepSessionInfo: true to passport.authenticate will preserve the session, i.e:
passport.authenticate('my-strategy', {
... ,
keepSessionInfo: true
})(req, res, next);
From the passportjs documentation, I can redirect to a URL
app.post('/login',
passport.authenticate('local', { successRedirect: '/',
failureRedirect: '/login' }));
Is it possible successRedirect should be another different domain suppose
my authentication is in www.auth.com after successful login I want to redirect to www.customer.com/callback with the data from www.auth.com.
It's actually like Facebook authentication with callback URL after successful login facebook POST data to the callback URL
app.get('/login', function(req, res) { //will handle if user fails to enter valid credentials
return res.render('login', {
message: 'Login Page Renderd...'
});
});
app.post('/login', passport.authenticate('local', {
successRedirect: '/profile', //will be redirected to `/profile` route after successful login
failureRedirect: '/login' //will be redirected to `/login` route for failure
}));
app.get('/profile', function(req, res) { //will handle if user enter valid credentials means user logged in successfully
return res.status(200).send('User Logged in successfully...');
});
Passport-Facebook we need to define callback url for successful & failure of authentication same as Passport-Local
I'm developing an app that has slack signin functionality.
I'm using passport-slack for OAuth but having some problem about routing which return Cannot GET /auth/slack
I followed the step by step procedure which can be found in https://github.com/mjpearson/passport-slack but still no luck
My current code for passport is like this which I think I define the routes correctly
// setup the strategy using defaults
passport.use(new SlackStrategy({
clientID: environment.SLACK.CLIENT_ID,
clientSecret: environment.SLACK.CLIENT_SECRET,
}, (accessToken, refreshToken, profile, done) => {
done(null, profile);
}));
// path to start the OAuth flow
app.get('/auth/slack', passport.authenticate('slack'));
// OAuth callback url
app.get('/auth/slack/callback',
passport.authenticate('slack', { successRedirect: '/',
failureRedirect: '/login' }));
/auth/slack is just a middleware for authentication, which means all the routes begin with /auth/slack will invoke this middleware.
Also because you don have any response for this route, and passport will just invoke the next() function, so Cannot GET /auth/slack
You should put /auth/slack/callback in your slack settings, slack will redirect the user to this route after the user sign in on slack
http://expressjs.com/en/guide/using-middleware.html
Getting this error when I successfully log in with passport JS. Trying to redirect to the home page once I log in.
Code that does it:
app.post('/login',
passport.authenticate('local', {failureRedirect: '/login' }),
function(req, res) {
res.redirect('/');
});
Full Error:
Error: Can't set headers after they are sent.
at ServerResponse.OutgoingMessage.setHeader (http.js:644:11)
Am I missing something? Not sure why this error is happening. I'm still able to use the app, I just dont want the error.
You are redirecting the user so serializeUser function is being called twice. And in
passport.use(new FacebookStrategy({
...
be sure to add this else or it gets called twice, thus sending the headers twice and causing error. Try this:
passport.use(new FacebookStrategy({
...
},
function(accessToken, refreshToken, profile, done) {
// asynchronous verification, for effect...
process.nextTick(function () {
// To keep the example simple, the user's Facebook profile is returned to
// represent the logged-in user. In a typical application, you would want
// to associate the Facebook account with a user record in your database,
// and return that user instead.
User.findByFacebookId({facebookId: profile.id}, function(err, user) {
if (err) { return done(err); }
if (!user) {
//create user User.create...
return done(null, createdUser);
} else { //add this else
return done(null, user);
}
});
});
}
));
According to the PassportJS guide, you're supposed to let their middleware do all of the redirects.
app.post('/login', passport.authenticate('local', { successRedirect: '/',
failureRedirect: '/login' }));
My guess is that the middleware is calling Express' res.redirect method just like you are in your example above, but has an error in its implementation (calling next when it shouldn't) and then your method is trying to call res.redirect again, and that causes the error to be thrown because you can only send a response to the client once in the HTTP protocol.