React-starter-kit: Adding a logout route

Created on 6 Jan 2017  路  7Comments  路  Source: kriasoft/react-starter-kit

I have added require('./logout').default, to routes/index.js and created routes/logout/index.js like so:

export default {
  path: '/logout',
  action({ req, res }) {
      req.session.destroy(function (err) {
        res.redirect('/');
      });
  },
};

But the req and res params are undefined. Is this a correct way to implement a logout route?

I would also prefer to use a post request for logout, can I send a post request to this route?

Most helpful comment

You can override default behavior like this:

function logout(event) {
  event.preventDefault(); // prevent page transition
  fetch('/logout', { method: 'POST' }).then(() =>
    window.location.reload() // stay at the same url
  )
}

<Link to="/logout" onClick={logout}>Logout Link</Link>
<a href="/logout" onClick={logout}>Logout Anchor</a>
<button type="button" onClick={logout}>Logout Button</button>
<form action="/logout" method="post" onSubmit={logout}>
  <button>Logout Form</button>
</form>

Also you can use redux action to logout user without page refresh:

const USER_LOGOUT = 'USER_LOGOUT'; // action type

function logout() { // redux action
  return (dispatch) => {
    dispatch({ type: USER_LOGOUT });
    return fetch('/logout', { method: 'POST' })
      .then(() => dispatch({ type: USER_LOGOUT, error: false }))
      .catch(error => dispatch({ type: USER_LOGOUT, payload: error, error: true }))
  }
}

const initialState = null;

function user(state = initialState, action) { // redux reducer
  switch (action.type) {
    case USER_LOGOUT:
      return action.error === false ? initialState : state;
    default:
      return state;
  }
}

There is not session auth in the master branch, so you can just clear cookie for logout:

/* src/server.js#L75 */
app.post('/logout', (req, res) => {
  res.clearCookie('id_token');
  res.redirect('/');
});

All 7 comments

These routes are used for isomorphic html rendering and executed on both server-side and client-side (in the browser).
Api routes like PUT, POST, etc. should exist on the server side only. For example you may find authentication api endpoints here: src/server.js

/* src/server.js#L75 */
app.post('/logout', (req, res) => {
  req.session.destroy();
  res.redirect('/');
});

I understand this, the reason I put it in routes/index.js was because I thought it could be done without refreshing the page.

But yeah, I guess there is nothing wrong with refreshing the page on logout. Thanks.

Any idea why there is no property session in req? ~Cannot read property 'destroy' of undefined (req.user exists and everything else seems ok)

You can override default behavior like this:

function logout(event) {
  event.preventDefault(); // prevent page transition
  fetch('/logout', { method: 'POST' }).then(() =>
    window.location.reload() // stay at the same url
  )
}

<Link to="/logout" onClick={logout}>Logout Link</Link>
<a href="/logout" onClick={logout}>Logout Anchor</a>
<button type="button" onClick={logout}>Logout Button</button>
<form action="/logout" method="post" onSubmit={logout}>
  <button>Logout Form</button>
</form>

Also you can use redux action to logout user without page refresh:

const USER_LOGOUT = 'USER_LOGOUT'; // action type

function logout() { // redux action
  return (dispatch) => {
    dispatch({ type: USER_LOGOUT });
    return fetch('/logout', { method: 'POST' })
      .then(() => dispatch({ type: USER_LOGOUT, error: false }))
      .catch(error => dispatch({ type: USER_LOGOUT, payload: error, error: true }))
  }
}

const initialState = null;

function user(state = initialState, action) { // redux reducer
  switch (action.type) {
    case USER_LOGOUT:
      return action.error === false ? initialState : state;
    default:
      return state;
  }
}

There is not session auth in the master branch, so you can just clear cookie for logout:

/* src/server.js#L75 */
app.post('/logout', (req, res) => {
  res.clearCookie('id_token');
  res.redirect('/');
});

@frenzzy directly sending the POST request works great! (the first snippet you have posted)
However I have been trying to make the second snippet to work as well (on feature/redux branch) and I am not sure how to dispatch the logout action.
The action from your snippet returns a callback to which a dispatch function should be passed however I am a little lost on how to do this.

Consider we are in navigation.js and add
<Link className={s.link} to="#" onClick={user_logout}>Logout</Link>
What I tried, is adding following function

import { logout } from '../../actions/user';

function user_logout () {
  var cb = logout();
  cb(dispatch);
}

The thing is, I don't know where to get the dispatch function (or store, which has it). How should I go about doing this?

You may use mapDispatchToProps inside react-redux connect(): Redux - Usage with React

Or dispatch manually:

class LogoutButton extends React.Component {
  static contextTypes = {
    store: PropTypes.object.isRequired,
  };

  handleClick = () => {
    this.context.store.dispatch(logout());
  };

  render() {
    return <button type="button" onClick={this.handleClick}>Logout</button>;
  }
}

Thanks! For anyone interested, this is what I did:
export default connect(state => ({ user: state.user }), dispatch => ({ logout_click: bindActionCreators(logout, dispatch) }))(withStyles(s)(NavLogin));

Also, I had to add credentials: 'same-origin' to the logout post like so:
return fetch('/logout', { method: 'POST', credentials: 'same-origin' })
Otherwise on page refresh it logged me back in on FE (I wasn't properly logged out)

Was this page helpful?
0 / 5 - 0 ratings