1

I'm working on my first express backend React frontend app. Currently working on the user register/login/logout section.

const express = require('express');
const mongoose = require('mongoose');
const bodyParser = require('body-parser');
const keys = require('./config/keys')
const passport = require('passport');
const session = require('express-session');
const LocalStrategy = require('passport-local');
// const passportLocalMongoose = require('passport-local-mongoose');
const User = require('./models/User');

const app = express();

// Use BodyParser
app.use(bodyParser.urlencoded({ extended: true }));

// Passport
app.use(passport.initialize());
app.use(passport.session());

app.use(session({
  secret: 'Rusty is the best',
  saveUninitialized: false,
  resave: false
}));

passport.use(new LocalStrategy(User.authenticate()));
passport.serializeUser(User.serializeUser());
passport.deserializeUser(User.deserializeUser());

// Connect to the Database
const db = keys.mongoURI
mongoose
  .connect(db, { useNewUrlParser: true })
  .then(() => console.log(`MongoDB connected...`))
  .catch(err => console.log(err));

// Routes
const items = require('./routes/api/items')
app.use('/api/items', items);

// Auth Routes
app.post('/register', function(req, res) {
  User.register(new User({ username: req.body.username }), req.body.password, function(err, user) {
    if (err) {
      console.log(err);
      return res.render('/register');
    }
    passport.authenticate('local')(req, res, function() {
      res.redirect('/secret');
    })
  })
});

app.post('/login', passport.authenticate('local', {
    successRedirect: '/secret',
    failureRedirect: '/login'
  }), function(req, res) {
});

app.get('/logout', function(req, res) {
  req.logout();
  res.redirect('/');
})

// Port and Listen
const port = process.env.PORT || 5000;
app.listen(port, () => console.log(`Server started on ${port}...`));

The post routes at the end of my express server.js file work fine, but I have problems when I get to app.get('/logout'). My server is running on 5000 and client is on 3000. I have "proxy": "http://localhost:5000" inside my client project.json. localhost:3000/logout returns a blank page while localhost:5000/logout returns the res.send message "You have hit the logout page".

Anyone know how I can fix this?

edit: Here is my react router to show how the client routes

import React, { Component } from 'react';
import { Route, BrowserRouter } from 'react-router-dom';

import Input from './components/Input';
import SignUp from './components/SignUp';
import Form from './components/Form';
import LogIn from './components/LogIn';
import SignUp2 from './components/SignUp2';
import Profile from './components/Profile';
import Home from './components/Home';
import LogOut from './components/LogOut';


class App extends Component {
  render() {
    return (
      <BrowserRouter>
        <div>
          <Route exact path='/' component={ Home } />
          <Route path='/register' component={ SignUp2 } />
          <Route path='/changeThisBackToRegister' component={ SignUp } />
          <Route path='/form' component={ Form } />
          <Route path='/login' component= { LogIn } />
          <Route path='/profile' component = { Profile } />
          <Route path='/secret' component = { Input } />
          <Route path='/logout' component = { LogOut } />
        </div>
      </BrowserRouter>
    );
  }
}

export default App;
oolongloop
  • 125
  • 1
  • 3
  • 12

1 Answers1

0

Change your /logout api response to send json response.

app.get('/logout', function(req, res) {
  req.logout();
  res.json({success: true});
})

In your Logout component, make /logout call when the component mounts.

import React, { Component } from 'react';

export default class Logout extends Component {
  constructor(props) {
    super(props);
    this.state = {
      logoutSuccess: false
    };

  }
  componentDidMount() {
    fetch('/logout')
    .then((response) => response.json())
    .then(() => {
      this.setState({logoutSuccess: true});
    });
  }
  render() {
    const { logoutSuccess } = this.state;
    return (
      <div>
        { logoutSuccess && (<div>Logout Success</div>)}
      </div>
    );
  }
}
Dinesh Pandiyan
  • 5,814
  • 2
  • 30
  • 49
  • Thank you @Dinesh Pandiyan! Would you mind quickly explaining what I was missing before and what your code fixes from a conceptual view? – oolongloop Dec 02 '18 at 11:17
  • 1
    React routes don't actually call the server. They happen within the browser and just the url is updated. So to logout, you actually have to call the logout endpoint in the server. That's why we're making an async call to the logout endpoint when Logout component is loaded. – Dinesh Pandiyan Dec 02 '18 at 12:14
  • Sounds great Dinesh! And what would be the best way to redirect the user back to '/home' at the end of the async call to the logout endpoint? – oolongloop Dec 03 '18 at 00:47
  • 1
    You need to programmatically navigate to `/home` when the `/logout` api call succeeds. Here's a good [SO answer](https://stackoverflow.com/a/42121109/3626796) on how to do it with React Router. – Dinesh Pandiyan Dec 03 '18 at 02:54
  • Thanks @Dinesh! So these options look like the user has to manually click a button to be redirected to /home, is there any way to do so automatically after the user is logged out of passport.js at the end of the API fetch call? – oolongloop Dec 05 '18 at 08:22
  • 1
    You can check redirect the user programmatically using the methods in the above comment in the success handler of api call. – Dinesh Pandiyan Dec 05 '18 at 08:32