Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Forcing login in react after 401 from backend

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.

like image 924
mrbox Avatar asked Jun 22 '18 14:06

mrbox


People also ask

How do I change the default routing in React?

Use the Navigate element to set a default route with redirect in React Router, e.g. <Route path="/" element={<Navigate to="/dashboard" />} /> . The Navigate element changes the current location when it is rendered. Copied!


2 Answers

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!')
    }
  )
like image 156
Matt Pengelly Avatar answered Oct 05 '22 22:10

Matt Pengelly


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.

like image 26
Simas.B Avatar answered Oct 05 '22 21:10

Simas.B