48

can't able to find solution of this tried everything, i am just new in using passport. Error: req#logout requires a callback function i have coded this before but that time i have not received any error, but this time dont know why i am getting this, i have also read passport docs and tried every solutions

thanks in advance

<%- include('partials/header') %>

<header>
    <nav class="flex align-item-center">
        <div class="div-left">
            <img id="userimg" src="img/user.png" alt="logo">
        </div>
        <div class="div-right flex">
            <div style="font-size: 14px">
                <a href="/logout" role="button"> Logout</a>
            </div>
        </div>
    </nav>
</header>

<%- include('partials/footer') %>

js code

require('dotenv').config();
const express = require("express");
const bodyParser = require("body-parser");
const ejs = require("ejs");
const mongoose = require("mongoose");
const session = require('express-session');
const passport = require('passport');
const passportLocalMongoose = require('passport-local-mongoose');
const GoogleStrategy = require('passport-google-oauth20').Strategy;
const findOrCreate = require('mongoose-findorcreate');

const app = express();

app.use(express.static("public"));
app.set('view engine', 'ejs');
app.use(bodyParser.urlencoded({
    extended: true
}));

app.use(session({
    secret: process.env.SECRET,
    resave: false,
    saveUninitialized: false
}))

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

mongoose.connect("#DB")

const accountsdata = new mongoose.Schema({
    email: String,
    password: String,
    googleId: String,
    facebookId: String,
    combo: String,
    date: String,
    price: String,
    accountemail: String

});

accountsdata.plugin(passportLocalMongoose);
accountsdata.plugin(findOrCreate);

const data = new mongoose.model("amazonprime", accountsdata);

passport.use(data.createStrategy());

passport.serializeUser(function (user, cb) {
    process.nextTick(function () {
        cb(null, { id: user.id, username: user.username });
    });
});

passport.deserializeUser(function (user, cb) {
    process.nextTick(function () {
        return cb(null, user);
    });
});

passport.use(new GoogleStrategy({
    clientID: process.env.CLIENT_ID,
    clientSecret: process.env.CLIENT_SECRET,
    callbackURL: "http://localhost:3000/auth/google/home",
    userProfileURL: "https://www.googleapis.com/oauth2/v3/userinfo"
},
    function (accessToken, refreshToken, profile, cb) {
        console.log(profile)
        data.findOrCreate({ googleId: profile.id }, function (err, user) {
            return cb(err, user);
        });
    }
));

app.get("/", (req, res) => {
    res.render("login");
});

app.get('/auth/google',
    passport.authenticate("google", { scope: ["profile"] })
);

app.get("/auth/google/home",
    passport.authenticate("google", { failureRedirect: "/" }),
    function (req, res) {

        res.redirect("/home");
    });

app.get("/signup", (req, res) => {
    res.render("signup");
});

app.get("/home", function (req, res) {
    if (req.isAuthenticated()) {
        res.render("home");

    } else {
        res.redirect("/");
    }
})

app.get("/logout", (req, res) => {
    req.logout();
    res.redirect("/");
});


app.post("/signup", (req, res) => {

    data.register({ username: req.body.username }, req.body.password, function (err, user) {
        if (err) {
            console.log(err);
            res.redirect("/signup");
        } else {
            passport.authenticate("local")(req, res, function () {
                res.redirect("/home");
            })
        }
    })
})

app.post("/", function (req, res) {

    const user = new data({
        username: req.body.username,
        password: req.body.password
    })
    req.login(user, function (err) {
        if (err) {
            console.log(err);
        } else {
            passport.authenticate("local")(req, res, function () {
                res.redirect("/home")
            })
        }
    })
});

app.get("/logout", (req, res) => {
    req.logout();
    res.redirect("/");
});




app.listen(3000, function () {
    console.log("Server started on port 3000.");
});

error

Error: req#logout requires a callback function
    at IncomingMessage.req.logout.req.logOut (E:\Web Development\Data Handler\node_modules\passport\lib\http\request.js:65:44)
    at E:\Web Development\Data Handler\app.js:105:9
    at Layer.handle [as handle_request] (E:\Web Development\Data Handler\node_modules\express\lib\router\layer.js:95:5)
    at next (E:\Web Development\Data Handler\node_modules\express\lib\router\route.js:144:13)
    at Route.dispatch (E:\Web Development\Data Handler\node_modules\express\lib\router\route.js:114:3)
    at Layer.handle [as handle_request] (E:\Web Development\Data Handler\node_modules\express\lib\router\layer.js:95:5)
    at E:\Web Development\Data Handler\node_modules\express\lib\router\index.js:284:15
    at Function.process_params (E:\Web Development\Data Handler\node_modules\express\lib\router\index.js:346:12)
    at next (E:\Web Development\Data Handler\node_modules\express\lib\router\index.js:280:10)
    at SessionStrategy.strategy.pass (E:\Web Development\Data Handler\node_modules\passport\lib\middleware\authenticate.js:346:9)
Harsh Gupta
  • 548
  • 1
  • 4
  • 10

10 Answers10

107

Since version 0.6.0 (which was released only a few days ago by the time of writing this), req.logout is asynchronous. This is part of a larger change that averts session fixation attacks.

See the release announcement:

The other major change is that that req.logout() is now an asynchronous function, whereas previously it was synchronous. For instance, a logout route that was previously:

app.post('/logout', function(req, res, next) {
  req.logout();
  res.redirect('/');
});

should be modified to:

app.post('/logout', function(req, res, next) {
  req.logout(function(err) {
    if (err) { return next(err); }
    res.redirect('/');
  });
});

Jared Hanson mentioned that the docs are not up to date yet:

It is necessary in order to improve the security of how sessions are managed during logout. Upgrading to 0.6.0 will require applications to pass a callback to req#logout. I'm still working on updating the docs and examples.

CherryDT
  • 25,571
  • 5
  • 49
  • 74
  • 1
    so `express-session` does not require a `req.session.destroy()` inside the `logout` logic? – Daniel Sep 23 '22 at 22:10
  • Thank you for the straightforward and simple explanation. I was following Colt Steele's Web Developer Bootcamp 2023 (specifically, Section 51) on Udemy, which was created before the changes took place, so not mentioned in the video. This solution relieved a lot of stress for me. Thank you!! – CSG Jan 11 '23 at 08:15
  • @HarshGupta: Thanks for suggesting an edit but it doesn't make sense. 1) This is a citation of the linked release notes article and it uses POST, so there it would be incorrect to write GET here. 2) It _should_ be POST and not GET because a logout changes state, and GET is not allowed to change state, it should only read state. – CherryDT Apr 22 '23 at 15:38
5

Learner here (too?) -- I had that same problem. I was banging my head against the wall until the instructor mentioned that req.login() requires a callback function. For the callback he used an error-handling function that turned out to work well for req.logout() too.

Maybe you could try this:

app.get("/logout", (req, res) => {
  req.logout(req.user, err => {
    if(err) return next(err);
    res.redirect("/");
  });
});
4

I have found this code in official passportjs and it worked for me I hope it will resolve your problem as well Passport exposes a logout() function on req

app.get('/logout', function(req, res, next){
    req.logout(function(err) {
      if (err) { return next(err); }
      res.redirect('/');
    });
  });
fitNrd
  • 41
  • 2
  • This worked for me as of today. Thanks for the docs link. The docs link suggests POST or DELETE but neither works for me. So used GET like you posted and it works. – Guzumba Aug 29 '23 at 17:48
2

If you are following Angela Yu web dev bootcamp, then use this,

app.get('/logout', function(req, res, next) {
  req.logout(function(err) {
    if (err) { 
      return next(err); 
      }
    res.redirect('/');
  });
});
  • I have been able to get it working with app.get but the passport documention says to use post or delete instead to prevent malicious attacks. I couldn't get app.post to work, I get an error that says "Cannot GET /logout". Is post really necessary, and if so, how do I get around this problem? My app.post looks like this... ```app.post('/logout', function(req, res, next) { req.logout(function(err) { if (err) { return next(err); } res.redirect('/'); }); });``` – tamio42 Aug 25 '22 at 02:38
1

This works perfectly for me:

app.get("/logout", function(req, res, next) {
  req.logout(function(err) {
    if (err) { return next(err); }
    res.redirect("/");
  });
});

and you can as well use this:

app.post("/logout", function(req, res, next) {
  req.logout(function(err) {
    if (err) { return next(err); }
    res.redirect("/");
  });
});

Both works, cheers!!!

1

if this is with Angela Yu bootcamp. use this:

https://www.passportjs.org/tutorials/password/logout/

app.get("/logout", function(req,res,next){
  req.logout(function(err){
    if (err)
    {
      return next(err);
    }
    res.redirect("/");
  });
});
Mustafa Poya
  • 2,615
  • 5
  • 22
  • 36
0
app.get('/users/logout', (req, res, next) => {
  req.logout(function (err) {
    if (err) {
      return next(err);
    }
    // if you're using express-flash
    req.flash('success_msg', 'session terminated');
    res.redirect('/login');
  });
});
Omar Dulaimi
  • 846
  • 10
  • 30
  • Please read [How do I write a good answer?](https://stackoverflow.com/help/how-to-answer). While this code block may answer the OP's question, this answer would be much more useful if you explain how this code is different from the code in the question, what you've changed, why you've changed it and why that solves the problem without introducing others. – Saeed Zhiany Jun 20 '22 at 02:44
0

here is my problem that is not working:

app.get("/logout", (req, res) => {
  req.logout();
  res.redirect("/");
});

The solution is:

require("dotenv").config();

const express = require("express");
const bodyParser = require("body-parser");
const ejs = require("ejs");
const mongoose = require("mongoose");
const session = require("express-session");
const passport = require("passport");
const passportLocalMongoose = require("passport-local-mongoose");

const app = express();
app.use(express.static("public"));

app.use(bodyParser.urlencoded({
  extended: true
}));

app.set("view engine", "ejs");

app.use(
  session({
    secret: "our little secret.",
    resave: false,
    saveUninitialized: false,
  })
);

app.use(passport.initialize());

app.use(passport.session());

mongoose.connect("mongodb://127.0.0.1/userDB");

const userSchema = new mongoose.Schema({
  email: String,
  password: String,
});

userSchema.plugin(passportLocalMongoose);

const User = new mongoose.model("User", userSchema);

passport.use(User.createStrategy());

passport.serializeUser(User.serializeUser());
passport.deserializeUser(User.deserializeUser());

app.get("/", (req, res) => {
  res.render("home");
});

app.get("/login", (req, res) => {
  res.render("login");
});

app.get("/register", (req, res) => {
  res.render("register");
});

app.get("/secrets", (req, res) => {
  if (req.isAuthenticated()) {
    res.render("secrets");
  } else {
    res.redirect("/login");
  }
});

app.get("/logout", function(req, res, next) {
  req.logout(function(err) {
    if (err) {
      return next(err);
    }
    res.redirect("/");
  });
});
Laaouatni Anas
  • 4,199
  • 2
  • 7
  • 26
0
<nav class="grey darken-3">
  <div class="nav-wrapper container">
    <a href="#!" class="brand-logo center">StoryBooks</a>
    <a href="#" data-target="mobile-demo" class="sidenav-trigger show-on-large"><i class="fas fa-bars"></i></a>
    <ul class="sidenav" id="mobile-demo">
      <li><a href="/stories">Public Stories</a></li>
      <li><a href="/dashboard">Dashboard</a></li>
      <li><a href="/auth/logout">Logout</a></li>
    </ul>
  </div>
</nav>
Tyler2P
  • 2,324
  • 26
  • 22
  • 31
  • It's important to not just post code, but to also include a description of what the code does and why you are suggesting it. This helps others understand the context and purpose of the code, and makes it more useful for others who may be reading the question or answer. – DSDmark Dec 31 '22 at 07:26
0
app.get("/logout", function(req, res, next) {
  req.logout(function(err) {
    if (err) {
      return next(err);
    }
    res.redirect("/");
  });
});

This works for me!

Tyler2P
  • 2,324
  • 26
  • 22
  • 31