Connorelsea
Connorelsea

Reputation: 2438

How to redirect after error inside of PassportJS/Express?

When configuring passport using Express and NodeJS, I am throwing an error if the user has an invalid email address. After this error I would like to redirect to a failure page giving them instructions on how to log in correctly. Is there are a better way to do this? If not, how would I go about catching the error in some fashion and redirecting to a new page.

passport.use(new GoogleStrategy({
        clientID     : auth.googleAuth.clientID,
        /* Settings redacted for brevity */
    },
    function(token, refreshToken, profile, done) {
        User.findOne(
            {
                "google.id" : profile.id
            },
            function(err, user) {

                if (err) return done(err)

                if (user) return done(null, user)

                else {

                    if (email.indexOf("lsmsa.edu") > -1) {

                        // Code redacted for brevity

                    } else {
                        done(new Error("Invalid email address"))
                    }
                }
            }
        )
    }))

Upvotes: 0

Views: 549

Answers (2)

BlackMamba
BlackMamba

Reputation: 10254

I think you can use this:

Redirects

A redirect is commonly issued after authenticating a request.

app.post('/login',
  passport.authenticate('local', { successRedirect: '/',
                                   failureRedirect: '/login' }));

In this case, the redirect options override the default behavior. Upon successful authentication, the user will be redirected to the home page. If authentication fails, the user will be redirected back to the login page for another attempt.

Or this:

Custom Callback

If the built-in options are not sufficient for handling an authentication request, a custom callback can be provided to allow the application to handle success or failure.

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);
});

Please read the document: https://www.passportjs.org/concepts/authentication/downloads/html/#middleware

Upvotes: 4

brandonscript
brandonscript

Reputation: 72865

Note: I quite like BlackMamba's answer as well, adding the custom callback / redirect is a perfectly acceptable option.

Simply add your own error handling middleware to Express:

passport.use(new GoogleStrategy({
    clientID     : auth.googleAuth.clientID,
    /* Settings redacted for brevity */
},
function(token, refreshToken, profile, done) {
    User.findOne({
            "google.id" : profile.id
        },
        function(err, user) {

            if (err) return done(err)

            if (user) return done(null, user)

            else {

                if (email.indexOf("lsmsa.edu") > -1) {

                } else {
                    // Throw a new error with identifier:
                    done(throw {
                        type: "invalid_email_address", 
                        code: 401, 
                        profileId: profile.id
                    }));
                }
            }
        }
    )
}));

// The error handling middleware:

app.use(function(e, req, res, next) {
    if (e.type === "invalid_email_address") {
        res.status(e.code).json({
            error: {
                msg: "Unauthorized access", 
                user: e.profileId
            }
        });
    }
});

You'll notice I modified this answer a little bit with a more robust error composition. I've defined the code property of the error to match the applicable HTTP status code -- in this case, 401:

// callback
done(throw {
    // just a custom object with whatever properties you want/need
    type: "invalid_email_address",
    code: 401, 
    profileId: profile.id
}));

In the error handling, we simply check the type is invalid_email_address (you can make it whatever you want, but it should be consistent across your app) and then write the error out using the "code" as the HTTP status code:

          // e is the error object, and code is the custom property we defined
res.status(e.code).json({
    error: {
        msg: "Unauthorized access",
        user: e.profileId
    }
});

Here's a self-contained working example with a redirect:

var express = require('express');
var app = express();

app.all('*', function(req, res) {
    throw {type: "unauthorized", code: 401}
})

app.use(function(e, req, res, next) {
    console.log(e);
    if (e.code === 401) {
        res.redirect("/login")
    } else {
        res.status(500).json({error: e.type});
    }
});

app.listen(9000);

Upvotes: 3

Related Questions