passport icon indicating copy to clipboard operation
passport copied to clipboard

DeserializeUser is not called.

Open SarasArya opened this issue 9 years ago • 22 comments

I am facing an issue in my main project. I tried to replicate the same issue in a small server project and it's working, can't figure out what's wrong with the big brother, so I started fiddling with the passport's session.js. So the difference I found out was. When from the correct code this file is called, there is a variable called su.

   var self = this, su;
   if (req._passport.session) {
   su = req._passport.session.user;
  }
  console.log(su+"su");`

So for the project it works. It gives the output 56699cf997f929f52959ddbasu But for the case where deserailzer user siltently fails It gives the answer. undefinedsu. What could possibly cause this?? In one project it's working. Exactly same stuff. But in one it is not. Please help

And also one more unexpected behaviour undefinedsu undefinedsu undefinedsu undefinedsu It is getting printed 4 times. Why the same function will be called 4 times??

Also one more behavior. In my bad app. Everytime I login a new session is created. But in my correct app it only logs it in once. So is it somethings to do with like it is not able to get data from the database??
I am trying to list out reasons , probably someone would have face it?

SarasArya avatar Dec 12 '15 15:12 SarasArya

I have the same issues. passport.deserializeUser() not getting executed and a new session id is created for each request. I have spent many hours trying to resolve this. I have read dozens of SO post dating back to 2012 and nothing I do resolves the issue. Express JS session and Passport are no where near as simple to use as the docs make it out to be. I have tried dozens of solutions from around the internet with no luck. Unfortunately I am trying to build a simple back end with node js to provide some API methods for a front end developer job interview and since I cannot make this technology work in a very simple scenario I guess I have to pass on the job opportunity.

jbeckton avatar Feb 09 '16 03:02 jbeckton

@jbeckton there is no reason to get disheartened so soon. Start a fresh project and stop changing that project. For me, it was working in other project and not in my original project. I don't know why. Try that hopefully, it will help. I will try posting a GitHub repo for such issues. Something like a starter kit for authentication which people can directly use.

SarasArya avatar Feb 09 '16 09:02 SarasArya

@jaredhanson could you look at this issue? Also I created a stackoverflow question and I am not the only one with this issue. Can you please suggest some steps to avoid it or give a working solution in some repo.

SarasArya avatar May 17 '16 17:05 SarasArya

Hey @jaredhanson came across this issue, see if you can pinpoint it in the source code. What I have observed is, whenever I make cross-origin request i.e. Let's say my server is running on port 7000 and a request is coming from my front end which is running on port 8080. Deserialize User is never called and when I create an index.html in my node.js folder and serve from there, deserialize user is called.

SarasArya avatar Jun 07 '16 10:06 SarasArya

@SarasArya Hi friend. I guess i have the same issue, My back i running in 4000 and my front in another port. How did you solve it ? remember ? thanks !!

marcoapferegrino avatar Dec 19 '17 21:12 marcoapferegrino

Hi guys,did anyone found out a solution to this situation? I've got a front and back end server running separately and i seem to have the same issue.

I also ran the following code to "bind" them:

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

I don't know if it "harms" anything,but at this point, i don't trust any line of code xD

Regards

mariog0ncalves avatar May 23 '18 23:05 mariog0ncalves

Hi guys! I had the same problem and resolved it!! Earlier I defined deserializeUser() in main file(the control point of run application) but always i had this problem. Then i turned to incapsulate all of passport code in function of another file and invoke that in main file. Now my code is working very nice. I hope this answer someone will help.

bublig737 avatar May 30 '18 16:05 bublig737

i ran into the same problem. I guess the route for which deserializeUser() is not called, would be using a middleware or express-router (basically you have app.use() instead of app.get() or app.post()).

The route would be something like=> app.use('/book',isAuthorized,booksRouter). where isAuthorized is a middleware and booksRouter is the router.

Now the deserialiseUser function is only called on app.get() or app.post() directly.

If you want to use app.use(), add passport.initialize() middleware like this: app.use('/book',passport.initialize(), isAuthorized, booksRouter)

Hope it clears your doubt!

SorcererSupreme avatar Dec 01 '18 07:12 SorcererSupreme

I ran into the same issue. The first thing to check is whether you have done:

app.use(passport.session())

This solved things for more, since deserializeUser() is part of the session logic in Passport. If you aren't using sessions then this will never be called.

PS adding this in case someone like me comes looking.

ajmas avatar Dec 06 '19 01:12 ajmas

In my case, I had put app.use(session{...}) after app.use(passport.session()). This order is wrong! Put app.use(session{}) before initializing passport. It worked fine for me

xenowits avatar Nov 19 '20 01:11 xenowits

@xenowits running into this issue as well. I do have my sessions declared in the order that you mentioned. What else made this work? Is Passport not supposed to be used inbetween two different apps? a frontend and a backend? because my frontend app doesn't seem to be creating the session correctly because my backend never hits seserializeUser.

normdoow avatar Nov 28 '20 00:11 normdoow

@normdoow check to see that that express is creating the session cookie and you see in the browser. Then do a simple session test by setting a session value and then seeing if you are seeing it next request. If you aren't then start investigating why the session value is not being held. Once you are sure that is working, then you can have another look at the passport behaviour.

ajmas avatar Nov 28 '20 01:11 ajmas

@ajmas Thanks for the help. I found that I wasn't passing a cookie from my client. Didn't know what I was doing there. Don't have it completely figured out but I think thats the issue.

I think a lot of people here are probably running into this because the passport docs don't mention how the sessions work very well. If you have a frontend and backend you probably need to pass the data in a cookie from the frontend. otherwise you will never call deserializeduser.

normdoow avatar Dec 02 '20 04:12 normdoow

@normdoow a pleasure.

Normally cookies are automatically sent back as part of the request, for same domain or same host. Do check what the context is set on the cookie. For example it could be set to a sub path on the server, instead of /.

ajmas avatar Dec 02 '20 05:12 ajmas

Just in case someone comes here with the same question this is what worked for me. Totally an order of operations thing.

  • The ilne where I set up cookieSession with app.use hast to be before the line where I initialize passport and passport sesstion. like this: `app.use( cookieSession({ maxAge: 30 * 24 * 60 * 60 * 1000, keys: [keys.cookieKey] }) );

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

BSlaven avatar Apr 25 '21 20:04 BSlaven

you must config session first then config after configinitialize() and session()

// config session first 
app.use(session({ 
    secret: 'something', 
    cookie: { 
        secure: true
    }}));
// after configinitialize() and session()
app.use(passport.initialize())
app.use(passport.session())

nguyenthanhson162001 avatar Jul 14 '21 15:07 nguyenthanhson162001

Hey i had the same issue and for me it was the cookie: { maxAge: 86400000, secure: true }you need to remove the secure: true and then it should work

Dyln01 avatar Aug 30 '22 09:08 Dyln01

@Dyln01 Hi, I have spend two days to find the answer, and I have found the answer in your comment. Thank you so much!!!!!

Vanlsh avatar Sep 24 '22 20:09 Vanlsh

I ran into the same issue. The first thing to check is whether you have done:

app.use(passport.session())

This solved things for more, since deserializeUser() is part of the session logic in Passport. If you aren't using sessions then this will never be called.

PS adding this in case someone like me comes looking.

worked for me

adamzar30 avatar Jan 08 '23 02:01 adamzar30

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: #570 Source: https://stackoverflow.com/a/72614577/17239746

Zirafnik avatar Jun 01 '23 12:06 Zirafnik

@Zirafnik so on every request you are making calls to your mongo store?

wmtrinu avatar Sep 23 '23 21:09 wmtrinu