ashishshenoy
ashishshenoy

Reputation: 95

Passport.js authentication inconsistent between Express routes

I am trying to use passport authentication with a local strategy provided by passport-local-mongoose to authenticate a user. If the user is authenticated, then he is allowed to view the /secret route, else he gets a bad request message (provided by passport).

The weird part is that the authentication works for the login POST route, which successfully redirects to the /secret page upon correct credentials. But on redirection, the user gets a bad request which means that authentication fails at the /secret route. This is very confusing as the user could only be redirected to /secret if he was successfully authenticated upon login, but upon redirection to /secret, authentication fails and a bad request error is sent.

User Schema:

const mongoose = require("mongoose"),
    passportLocalMongoose = require("passport-local-mongoose");

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

userSchema.plugin(passportLocalMongoose);

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

Server Configuration:

const express = require("express"),
    mongoose = require("mongoose"),
    passport = require("passport"),
    bodyParser = require("body-parser"),
    LocalStrategy = require("passport-local"),
    expressSession = require("express-session");

const User = require("./models/user");

const app = express();

app.set("view engine", "ejs");
app.use(
    expressSession({
        secret: "Lorem Ipsum",
        resave: false,
        saveUninitialized: false
    })
);
app.use(bodyParser.urlencoded({ extended: true }));
app.use(passport.initialize());
app.use(passport.session());

mongoose.connect("mongodb://localhost:27017/auth-test", {
    useNewUrlParser: true,
    useUnifiedTopology: true
});

passport.use(new LocalStrategy(User.authenticate()));
passport.serializeUser(User.serializeUser());
passport.deserializeUser(User.deserializeUser());

Login and Secret Routes:

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

app.get("/secret", passport.authenticate("local"), (req, res) => {
    res.render("secret");
});

Login form in case it is needed, used on the /login GET route:

<form action="/login" method="POST">
    <input type="text" placeholder="Username" name="username" autocomplete="off" />
    <input type="password" placeholder="Password" name="password" autocomplete="off" />
    <button type="submit">Submit</button>
</form>

Upvotes: 0

Views: 247

Answers (1)

MAS
MAS

Reputation: 736

Checking passport-local code, it seems that Authenticate() is used to verify the user's credentials (username, password), so basically you'll only need to use it in /login route.

To verify if the user is authorized to access a protected route, you can use req.isAuthenticated() instead.

Example:

app.get("/secret", (req, res) => {
  if (!req.isAuthenticated()) {
    return res.sendStatus(401);
  }
  res.render("secret");
});

Upvotes: 1

Related Questions