Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

"deserializeUser" not called with CORS. when FE & BE serve on different ports #570

Open
Marshevskyy opened this issue May 11, 2017 · 22 comments

Comments

@Marshevskyy
Copy link

My app is being served from a different port (FE side) than my API server (BE side). I am using passport to authenticate the user of the API. Looks like "deserializeUser" not called with CORS. I've already tried add to FE request "withCredentials" option, but without luck.

btw When I tested my BE server with POSTMAN, all work fine, "deserializeUser" was called, and req.user has beed returned (it means that I setted up server correctly). But if you need my server.js config, I can sent it out, just le me know.

I also using "passport-local" strategy, maybe there is a problem....

is it possible to get "passport" workable with CORS app? I want to have getting "req.user" in each request =), because, for now I can get in only right after passport.authenticate('local-login'....... -> req.login -> req.user

pls help

@marcoapferegrino
Copy link

Hi guys is there any solution?

I have my front in one port and my back in other but deserialize is not being called. I tried credentials true in my cors but did not work. Thanks for your answers

@Marshevskyy
Copy link
Author

Marshevskyy commented Dec 22, 2017

hey @marcoapferegrino. It is not working so far. I've found workaround, once user logs in, user saved into cache
const mcache = require('memory-cache');
setCurrentUser: function (token, user) { mcache.put(token, JSON.stringify(user)); }
then I can get user by token in any places I want

@YoshiYo
Copy link

YoshiYo commented Jan 9, 2018

Same problem here.
With postman it works, but with the localhost juste the serialize is called.
I tried everything.

Any solution ?

@aaomidi
Copy link

aaomidi commented Jan 31, 2018

I'm having this issue as well.

@bnerDY
Copy link

bnerDY commented Feb 12, 2018

Same problem here.

@aaomidi
Copy link

aaomidi commented Feb 12, 2018

My problem was that the cookie was not being set properly on client side. CORS is fine. Ports are fine.

@marcoapferegrino
Copy link

I set credentials true in my Vue component and also I did the normal configuration for cookies. My problem was the cookie was not set correctly or was not sent correctly. I hope this helps you guys

@Bitpocketer
Copy link

Same issue, spent whole day trying to figure it out no luck, with postman it works fine.

@aaomidi
Copy link

aaomidi commented Feb 18, 2018

@Bitpocketer it's most likely an issue with your client not sending the proper cookies back.

@Bitpocketer
Copy link

@aaomidi thank you very much, but could you please guide me what needs to be done, I'm very new to web development, I have very little idea of cookies and cookie parser, but why does it work fine for other strategies like facebook and google i have no idea, it is only local strategy that is problematic.

@aaomidi
Copy link

aaomidi commented Feb 19, 2018

@Bitpocketer I'm personally new too, but you need a few headers to enable credential passing to origin, and making sure you're setting the cookies.

@bnerDY
Copy link

bnerDY commented Feb 21, 2018

I solved my problem with sending request with "withCredentials: true". Everything works fine then. Hope that helps

@adamgen
Copy link

adamgen commented Jun 2, 2018

Same issue

@almondevon
Copy link

I'm having this issue as well. The client cookie doesn't seem to be the issue, the passport object just isn't saved inside of the MemoryStore when coming from a CORS browser, however it is with Postman. I'll keep digging and will report back with any other clues.

@adamgen
Copy link

adamgen commented Jun 7, 2018

I eventually walked around using a JWT.

Here's an example, instead of passport.authenticate('local') to identify if the user is logged in , I used the callback under the /me route as a middleware. Also on the login route I used passport.authenticate('local', {session: false}) so it won't try to keep track of the session itself.

https://gist.github.com/adamgen/d79e3148913bb7ee609fb7c589e94e8e

On the client, after a successful login I save the token on localStorage and I send it with every request that need permissions.

@rewantkedia
Copy link

My problem was that the cookie was not being set properly on client side. CORS is fine. Ports are fine.

How did you solve it ?

@aaomidi
Copy link

aaomidi commented Jan 28, 2019

How did you solve it ?

Read what I sent earlier :P

@rewantkedia
Copy link

rewantkedia commented Jan 29, 2019

Working on sending {withCredentials:true} parameter along with every request from the frontend so that the frontend sends cookie along with every request.

Added the following code in the backend:

app.use(cors());

app.use(function(req, res, next) {
res.header("Access-Control-Allow-Origin", "frontendURL");
res.header("Access-Control-Allow-Credentials", true);
res.header(
"Access-Control-Allow-Headers",
"Origin, X-Requested-With, Content-Type, Accept"
);
next();
});

Example front-end request for login handle:

const login_axios = axios.create({
withCredentials: true,
headers: {
Accept: "application/json",
"Content-Type": "x-www-form-urlencoded"
},
params: {
username: this.state.username,
password: this.state.password
}
});
login_axios
.post()
.then(function(response) {
console.log("RESPONSE");
console.log(response);
})
.catch(function(error) {
console.log("ERROR");
console.log(error);
});

@gabgagnon
Copy link

Don't forget to call the fonction req.logIn(user, () => {}); during the authentication! The doc is lying, passport.authenticate() middleware DOES NOT invokes req.login() automatically.

passport.serializeUser and passport.deserializeUser will never be call if you don't call this fonction by yourself!

5 hours for this...

@pavan-sagar
Copy link

Hi All, I had this exact same problem and literally spent an entire day pulling my hair. Passport was recognising session when sending request from Postman but not from the frontend. My Frontend was on port 3000 and backend on 3001. I solved the problem by following below steps :

Step 1. Setting with credentials flag to true in the axios request from FE
{withCredentials:true}

This will make sure that cookies are sent when making a request to cross origin BE (as they are running on different ports).

Step 2: Enabling such requests from an allowed origin in BE cors option

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

Original Credit --> https://stackoverflow.com/questions/43002444/make-axios-send-cookies-in-its-requests-automatically

@Cristos123
Copy link

My problem was that the cookie was not being set properly on client side. CORS is fine. Ports are fine.

How did you set the Cookie in front end

@Zirafnik
Copy link

Zirafnik commented Jun 1, 2023

For every other lost soul out there, this is what was going on in my case and how I fixed it.

I have a React FE, served on: localhost:3000
and an Express BE, served on: localhost:5000

In Express I am using Passport with 'local' strategy and a persistent session-store (Redis). I have also configured cors, to allow sending credentials from the frontend.

app.use(cors({
   origin: 'http://localhost:3000`,
   credentials: true,
   allowedHeaders: ['Content-Type'], // this is needed for sending JSON
}));

So like everybody else here, I was having problems with Passport not deserializing users. On the frontend to successfully send back the session cookie back I did:

fetch('http://localhost:5000/private', { credentials: 'include'} );

So, I was successfully receiving the connect.sid cookie on the backend, which is used for session identification, but the user never got set. Now stupidly, because of the passport.deserialize function's description ("Registers a function used to deserialize user objects out of the session"), I thought this is also the function which queries the session-store (in my case Redis) with the correct sessionId to retrieve the UserId, and then we query our database (in my case MongoDB) for the actual user data to be set on req.user. This, however, is not the case: passport.deserialize only does the second part: finding the user in MongoDB, only if it successfully received a UserId as a parameter from the session-store from some other function.

Now why was I receiving undefined if I had the session saved in session store (Redis) and the cookie with SID was being sent back to backend?

Well here's the kicker, contrary to what the name suggests { credentials: 'include'} should not only be specified when you want to send back the credential cookies, BUT also when you first make the authentication request and are RECEIVING said cookies. So for it to work you need set credentials: include while both receiving and sending the cookies.

What actually happened: On successful authentication Express was sending back an authenticated cookie, but because my POST authentication request did not include credentials: 'include' option, the browser never set the cookie. On the next GET request to a '/private' route, because the cookie was not set, Express sent a new default cookie. That was the cookie I was seeing that was being sent back - but I was sending the incorrect cookie.

All I needed to change was adding credentials: 'include' to POST:

fetch('http://localhost:5000/login', {
        method: 'POST',
        headers: {
            'Content-Type': 'application/json',
        },
        body: JSON.stringify(body),
        credentials: 'include', // this is needed for browser to set the cookie it receives
    });

So in short, always use credentials: 'include' option (or with axios withCredentials: true) both when RECEIVING and setting cookies, as well as when SENDING them.

Related: #446
Source: https://stackoverflow.com/a/72614577/17239746

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests