0

I am currently developing a node/express server, and I decided to use passport-local for user authentication along with a local MongoDB server. I am using a POST method from an html form to send the two items, an email and a password (I changed the usernameField item in my instance of LocalStrategy). Using console.log's, I've seen all of the correct and expected behavior from Mongo and Passport. However, the page never redirects with successRedirect or failureRedirect. It looks like the html page (Login.html) just refreshes. Interestingly, I get different behavior depending on how I decide to make the POST request from the form. Originally, I used jQuery and a $('#id').submit() method to call a $.post request at '/students', and I observed the behavior mentioned above. However, when I got rid of this script and used to send the request, none of the middleware was called (again, I confirmed this using console.log's), and the page immediately redirected to my failureRedirect url, regardless of whether I entered valid data in the form.

Note: 'Student' is the name of my mongoose model, the problem isn't with that

Things I've already tried: 1. Using a custom callback with my passport.authenticate and using res.redirect. In fact, I placed a console.log inside this function to see if it was called, and it was. But the res.redirect flat out didn't work. 2. Getting rid of my custom usernameField and passwordField and just using the default. I observed the exact same behavior. 3. Using a jQuery .click() method rather than an a .submit() one. I thought submitting the form had something to do with refreshing the page, but this didn't work.

Things I think may help but I don't know how to implement: 1. Changing the order of all of my serverside Javascript (maybe somethings isn't getting called correctly) 2. I saw somewhere that passport.authorize was used instead of passport.authenticate

In app.js

app.use(passport.initialize());
app.use(passport.session());

passport.use(new LocalStrategy({
    usernameField: 'email',
    passwordField: 'password'
  },
(username, password, done) => {
    console.log(username, password);
    Student.findOne({ email: username, password:password }, function(err, user) {
        console.log(user); //this works as expected
        console.log(!user); //this works as expected
        if (err) { return done(err); }
        if (!user) {
          return done(null, false, { message: 'Incorrect username.' });
        }

        if (user.password != password) {
          return done(null, false, { message: 'Incorrect password.' });
        }

        return done(null, user);
      });
}));

passport.serializeUser(function(user, done) {
  done(null, user.id);
});

passport.deserializeUser(function(id, done) {
  Student.findById(id, function(err, user) {
    done(err, user);
  });
});

app.post('/students', passport.authenticate('local', { 
    successRedirect:'/public/Schedule.html',
    failureRedirect:'/' 
}));

In the script tag of Login.html

$('#loginForm').submit(() => {
    let currentUser = {
         email: $('#email').val(),
         password: $('#password').val()
    }

    checkForUser(currentUser);
});

function checkForUser(user) { 
    $.post('http://localhost:9000/students',user, (data) => { 
         console.log(data);
    })
}
naevich
  • 3
  • 2

1 Answers1

1

An Ajax call from the Javascript in a web page does not automatically redirect based on the http response. Things that redirect automatically are things where the call to the server is not directly from Javascript such as clicking on a link, submitting a form (without Javascript), typing an URL into the URL bar, etc...

Instead when a request is sent from Javascript (as yours appear to be), the Javascript gets the response back and that response is available to your Javascript. If you see it's a 302 and you want to redirect, then you get the location header and set window.location to that redirect URL to cause the page to redirect.

jfriend00
  • 683,504
  • 96
  • 985
  • 979
  • Thanks, but what does the syntax look like for that? As far as I can tell, the "data" that is sent back to the JS is HTML and not a link (which makes sense). I am not really sure how to get the URL out of that. Also, do you have any idea why the page would immediately redirect to the failureRedirect URL when I use the form attributes (method and action) to send the request? That is the most confusing part about this to me: when I send the request using Javascript, the redirect doesn't immediately happen, but when I send it from the form submission, it skips all of the Passport.js code entirely – naevich Jun 12 '19 at 03:40
  • @naevich - Since you're using jQuery for your ajax, you can do a little jQuery studying to see how to get response headers from a jQuery ajax call. Here's [one example](https://stackoverflow.com/a/53391936/816620) and you can read about `jqXHR.getResponseHeader()` [here](http://api.jquery.com/jquery.ajax/). – jfriend00 Jun 12 '19 at 03:50
  • @naevich - The form submission is likely not sending the correct request to the server. You can use the network tab in Chrome to examine both requests and see what the differences are. The form (method and action) does follow redirects. The Ajax does not. – jfriend00 Jun 12 '19 at 03:55
  • FYI, it's actually easier to do the redirect from jQuery Ajax Javascript is you just return a regular JSON response with a 200 response code and then your client-side Javascript can just examine the response, see that a redirect is recommended (from a value set in the JSON object) and then grab the redirect URL from the same JSON object. You'd change your server to return the JSON object instead of setting a 302 redirect. – jfriend00 Jun 12 '19 at 03:58