14

I'd like to use react with following flow:

  • user is doing something
  • user tries to open page required authentication
  • frontend sends request to server(ie get list of some objects)
  • if user is authenticated server responds with list of objects, state is updated and everyone is happy
  • if user is not authenticated server responds with 401 unauthorized, I want to show login form(page), perform login and redirect to originally requested page

Thing that I have now is:

App.js:

class App extends Component {
  render() {
    return (
      <BrowserRouter>
        <Switch>
          <Route exact path="/login" name="Login Page" component={Login} />
          <Route path="/private" name="Private page" component={PrivatePage}/>
          <Route path="/" name="Home" component={Index} />

        </Switch>
      </BrowserRouter>
    );
  }
}

PrivatePage.js:

import api from '../../api';
class PrivatePage extends Component {
  state = {
    first_name: '',
    last_name: ''
  };
  componentDidMount() {
      api.getProfile().then((res) => { /* this needs to be executed only if status code was 200 */
        this.setState({
          first_name: res.first_name,
          last_name: res.last_name
        })
      })
  }

  render() {
    return (
      <div>
        <p>first name: {this.state.first_name}</p>
        <p>last name: {this.state.last_name}</p>
      </div>
    );
  }
}

Api.js:

export class Api {

  getProfile(){
    return fetch('http://some_endpoint.com', {
        method: 'GET',
        body: '{}'
    })
    .then(/* probably something here needs to redirect to Login page in case of 401? */)
  }

}
let api = new Api();
export default api;

This is of course simplified version of code- but shows my intention.

mrbox
  • 814
  • 1
  • 6
  • 18

3 Answers3

3

I'd suggest wrapping your Route components, the ones which needs to be protected, in some custom ProtectedRoute component which would access redux state, or would get some isAuthenticated prop, and then render Route. Protected routes.

Then on receiving 401 in your api call, just change isAuthenticated in state, or redux-state or whereever you're storing it.

Simas.B
  • 724
  • 1
  • 13
  • 31
  • this is actually something that I want to avoid- keeping global state of authentication of user is not that good idea in my opinion – mrbox Jun 23 '18 at 14:49
  • @mrbox why not, out of interest? it seems like something that various part of an app would want to know. – Nick Cox Sep 25 '19 at 03:43
  • If you refresh the page, the Store is cleaned-up though, so you'll need to re-login again. – George Katsanos May 28 '20 at 17:15
2

I think there are two ways.

Redirect from the backend. Or redirect on the front end via react-router (since youre using react-router)

using react router on the front end:

  getProfile(){
    return fetch('http://some_endpoint.com', {
        method: 'GET',
        body: '{}'
    })
    .then(/* probably something here needs to redirect to Login page in case of 401? */)
    .catch((err)=>{
      // you should get unauthorized.
      this.setState({redirecting: true}) // this state is set which will render a react component called Redirect from react router
    })
  }

then in your render (note: youll need to import this)

render() {
   return (
     if(redirecting){
       <Redirect to="/login"> 
     }
     // other stuff
   )
}

for docs see: https://github.com/ReactTraining/react-router/blob/master/packages/react-router/docs/api/Redirect.md

using express backend when you setup your authentication (here im using passport):

  app.post(
    '/api/login',
    passport.authenticate('local', {
      // successRedirect: '/profile',
      // failureRedirect: '/error'
    }),
    (req, res) => {
      res.send('authenticated!')
    }
  )
Matt Pengelly
  • 1,480
  • 2
  • 20
  • 34
  • 3
    Thanks- but this would mean that I need to make my Api class a component to use setState? As you see, Api is just a class- so in my head it would have to modify some global state because otherwise I'd have to put redirection logic in each of my components, right? Indeed, I'd like to use react router on the frontend side instead of backend redirect. – mrbox Jun 23 '18 at 14:54
-2

You have to check the status code returned from your request and then, if status is 401 you should redirect to login page using react router.

Here is a answer about how to redirect programmatically with react router

Lucas Milotich
  • 370
  • 3
  • 15