Reputation: 1151
Why is it that on refresh, my user is no longer authenticated or returns false? It seems like the data in my user store is being reset or tossed out. For example this is my actions :
class UserActions {
manuallogin(data) {
this.dispatch();
UserWebAPIUtils.manuallogin(data)
.then((response, textStatus) => {
if (textStatus === 'success') {
this.actions.loginsuccess(data.email);
}
}, () => {
});
}
loginsuccess(email) {
this.dispatch(email);
}
logout() {
this.dispatch();
UserWebAPIUtils.logout()
.then((response, textStatus) => {
if (textStatus === 'success') {
this.actions.logoutsuccess();
}
}, () => {
});
}
logoutsuccess() {
this.dispatch();
}
}
export default alt.createActions(UserActions);
and my store is this..
class UserStore {
constructor() {
this.user = Immutable.Map({});
this.on('init', this.bootstrap);
this.on('bootstrap', this.bootstrap);
this.bindListeners({
handleLoginAttempt: UserActions.MANUALLOGIN,
handleLoginSuccess: UserActions.LOGINSUCCESS,
handleLogoutAttempt: UserActions.LOGOUT,
handleLogoutSuccess: UserActions.LOGOUTSUCCESS
});
}
bootstrap() {
if (!Immutable.Map.isMap(this.user)) {
this.user = Immutable.fromJS(this.user);
}
}
handleLoginAttempt() {
this.user = this.user.set('isWaiting', true);
this.emitChange();
}
handleLoginSuccess() {
this.user = this.user.merge({ isWaiting: false, authenticated: true });
this.emitChange();
}
handleLogoutAttempt() {
this.user = this.user.set('isWaiting', true);
this.emitChange();
}
handleLogoutSuccess() {
this.user = this.user.merge({ isWaiting: false, authenticated: false });
this.emitChange();
}
}
// Export our newly created Store
export default alt.createStore(UserStore, 'UserStore');
I check if my user is authenticated by simply doing User.getState().user.get(authenticated), after login it comes back true, however if I type in any url manually or refresh the page it returns false afterwards. I am also using react-router and I think this is where it falls apart.
<Route>
<Route name ="dash" path="/dashboard" handler={App}>
<Route name ="dashboard" path="/dashboard" handler={Dashboard}/>
<Route name ="reports" path="/reports" handler={Report} />
<Route name ="employees" path="/employees" handler={Employees}/>
<Route name ="MyEmployees" path="/MEmployees" handler={MyEmployees}/>
<Route name ="AllEmployees" path="/AEmployees" handler={AllEmployees}/>
<Route name ="Profile" path="/profile" handler={Profile}/>
<Route name ="reportstocomplete" path="/reportsc" handler={ReportsToComplete}/>
<Route name ="addReport" path="/addReport" handler={AddReports}/>
<Route name ="readme" path="/readme" handler={Readme}/>
<Route name ="statistics" path="/statistics" handler={Stats}/>
<Route name ="signup" path="/signup" handler={Signup} />
<Route name ="login" path="/" handler={Login} />
</Route>
</Route>
After login, it rerenders the screen if succesfull and allows the user to head to the dashboard, once I'm there the user is still 'authenticated', I can navigate to any route by the buttons I click on the webpage or the buttons on the navbar (via react-router). If I however, refresh, click on a link, or manually type in /dashboard or /posts it will show that the state of the user is not authenticated in the console. Do I store the user info in local storage or something? I'm using mongo to save user data and that is working fine, but its pretty frustrating when you can't figure out why something even works like this..
Upvotes: 1
Views: 475
Reputation: 1151
I figured out what the problem was. On the server I save the session into a cookie with cookieparser and I had set the secure option to true. Therefore it wouldnt create the cookie over anything that wasn't https. Localhost doesnt run on https, which is why it would continue to forget the user in my store.
app.use(cookieParser());
// Create a session middleware with the given options
// Note session data is not saved in the cookie itself, just the session ID. Session data is stored server-side.
// Options: resave: forces the session to be saved back to the session store, even if the session was never
// modified during the request. Depending on your store this may be necessary, but it can also
// create race conditions where a client has two parallel requests to your server and changes made
// to the session in one request may get overwritten when the other request ends, even if it made no
// changes(this behavior also depends on what store you're using).
// saveUnitialized: Forces a session that is uninitialized to be saved to the store. A session is uninitialized when
// it is new but not modified. Choosing false is useful for implementing login sessions, reducing server storage
// usage, or complying with laws that require permission before setting a cookie. Choosing false will also help with
// race conditions where a client makes multiple parallel requests without a session
// secret: This is the secret used to sign the session ID cookie.
// name: The name of the session ID cookie to set in the response (and read from in the request).
// cookie: Please note that secure: true is a recommended option.
// However, it requires an https-enabled website, i.e., HTTPS is necessary for secure cookies.
// If secure is set, and you access your site over HTTP, the cookie will not be set.
app.use(session({
resave: true,
saveUninitialized: true,
// Use generic cookie name for security purposes
key: 'sessionId',
secret: secrets.sessionSecret,
// Add HTTPOnly, Secure attributes on Session Cookie
cookie: {
httpOnly: true,
secure: true
},
store: new MongoStore({ url: secrets.db, autoReconnect: true})
}));
app.use(passport.initialize());
app.use(passport.session());
app.use(flash());
Just got rid of the httpOnly and secure part of cookie since it only runs over https
Upvotes: 1