10

I'm moving a project over to Vue.js and I can't get any of my middleware to check if users are logged in or to check user ownership of things to work. After searching endlessly, I believe that the problem is that the headers I send from my client to server don't contain the passport serialized user or something? How can I make this work?

Here is my login route on the back-end:

      router.post("/login", function (req, res, next) {
    if (!req.body.username || !req.body.password) {
      res.send("Error");
    } else if(req.body.username.length > 40 || req.body.password.length > 40){
      res.send("Error");
    } else if (req.body.username) {
      req.body.username = req.body.username.toLowerCase();
      next();
    }
  }, passport.authenticate('local', {
    failureRedirect: '/login'
  }), function(req, res){
        User.findById(req.user.id, function(err, user){
          if(err){
            res.send("User not found");
          } else {
            res.send(user.toJSON());
          }
        })
  });

Here is my login page on the client side:

          async login () {
          const response = await AuthenticationService.login({
                username: this.username,
                password: this.password,
            })
            if(response.data == "Error"){
                this.$router.push({
                    name: 'login'
                })
            } else {
            this.$store.dispatch('setUser', response.data._id);
            this.$router.push({
                name: 'home'
            })
            }
        }

Here is the axios call that AuthenticationService.login is referencing:

    login(credentials){
    return Api().post('login', credentials);
},

Api comes from:

import axios from 'axios';

 export default function(){
   return axios.create({
      baseURL: `http://localhost:8081/`
   });
  }

So how do I make the front-end send the right headers to the back-end after a user is authenticated? As you can see, I store the user id in a vuex state, but I don't think that would be safe to use to confirm ownership and whether or not users are logged in, right? Or would it? I could easily just send that over in the requests, is that right? I feel like that's not safe enough, but Idk what I'm talking about.

EDIT: Here is the passport setup in app.js

app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());
app.use(cors());
app.use(flash());
app.use(cookieParser());

app.use(express.session({ //5a6ba876578447262893ac69
    secret: "sessionSecret",
    resave: false,
    saveUninitialized: false
  }));
app.locals.moment = require('moment');
app.use(passport.initialize());
app.use(passport.session());
passport.use(new LocalStrategy(User.authenticate()));
passport.serializeUser(User.serializeUser());
passport.deserializeUser(User.deserializeUser());
11
  • For sessions to work in passport/express, you need to define [de]serializeUser on the passport instance . Can you show all of the express/passport middleware you are using? Commented Jul 28, 2018 at 0:10
  • As for storing the user id in vuex state, that's totally fine as long as you use that for UI purposes (and not authoritative). You should store the users session token in cookies which are HttpOnly and use those to authenticate/authorize the user on the server side. Commented Jul 28, 2018 at 0:11
  • Thanks for the edit. What happens on the server side when you attempt to access POST /login? Commented Jul 28, 2018 at 0:16
  • Thank you, Dan. I included the passport and express middleware in an edit above, however I think my issue is solely based on your second comment. How to I get the token? How do I save it? And how do I use it in other requests? Commented Jul 28, 2018 at 0:16
  • When I attempt to access POST/login t works exactly as it should Commented Jul 28, 2018 at 0:17

2 Answers 2

8

Your issue is because your frontend and backend are on different domains.

Cookies, which passport.session()/express.session() use to maintain a user session, are scoped to a specific domain.

When you call axios.get() on the protected resource, axios will not send or receive cookies because localhost:8080 is a different domain to localhost:8081.

Try axios.get('/path/to/your/resource', { withCredentials: true }) and axios.post('/login', { username, password }, { withCredentials: true })

This would have been present even without Vue so long as you're using AJAX to make these calls.

Sign up to request clarification or add additional context in comments.

7 Comments

I think this is probably it, thank you, Dan! But now I'm getting a cors error, do you know how to get around it?
Failed to load localhost:8081/login: Response to preflight request doesn't pass access control check: The value of the 'Access-Control-Allow-Origin' header in the response must not be the wildcard '*' when the request's credentials mode is 'include'. Origin 'localhost:8080' is therefore not allowed access. The credentials mode of requests initiated by the XMLHttpRequest is controlled by the withCredentials attribute.
You'll need to set the CORS headers. github.com/expressjs/cors. You should them to localhost:8080 for now.
I already have app.use(cors()) in my app.js on the backend. Do I need to add that somewhere in the frontend too? If so, where exactly at?
No, it's a backend thing. As your error message mentions, you need to enable pre-flight requests, which is documented here
|
3

requests.js

let axiosConfig = {
  withCredentials: true,
  headers: {
    'Content-Type': 'application/json',
    'Access-Control-Allow-Origin': 'http://localhost:3000/',
    'Access-Control-Allow-Methods': 'GET,PUT,POST,DELETE'
  }
}

server.js

var express  = require('express');
var app      = express();
var cors = require('cors');
app.use(cors({credentials: true, origin: 'http://localhost:8080'}))

app.use(cors({credentials: true, origin: 'http://localhost:8080'}))

1 Comment

thanks! i was missing the credentials: true in server

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.