I'm currently developing an application using the MERN stack with Passport.js for authentication, specifically Google OAuth2 Strategy. My current application has simple login functionalities that redirects from client to the Google consent page and back to the server's redirect url, which should then redirect to client's main app. I'm pretty sure that's all you need to do in the server side and now I'm slightly confused as to how to handle this on the React Router side.
So first, I have my Google Sign-in button in my Public route which then hits the endpoint in the server that triggers the Google OAuth
class Public extends Component {
render() {
return (
<div>
<h1>Public Route</h1>
<a href="http://localhost:5000/api/auth/google">Sign In</a>
</div>
)
}
}
After the server redirects from localhost:5000/auth/google/redirect to localhost:3000/protected, I believe it goes back to App.js that triggers the React router
class App extends Component {
constructor(props) {
super(props)
this.state = { authenticated: false }
}
componentDidMount() {
api.get('/auth/user').then(({data}) => {
if (data) this.setState({authenticated: true})
}).catch((err) => console.error(err))
}
render() {
const { authenticated } = this.state
return (
<div className="App">
<Switch>
<Route exact path='/' component={Public} />
<PrivateRoute exact authed={authenticated} path='/app' component={Protected} />
</Switch>
</div>
)
}
}
and this this is where things get a little messy. So I think it's going to render first before componentDidMount(), so authenticated state is still false so PrivateRoute redirects the client back to localhost:3000/ and renders the Public route. And then after all that, runs componentDidMount() and finally fetches the user and now authenticated is true, but it's too late now since the client was already redirected to localhost:3000/ so it's not hitting the PrivateRoute anymore.
Here's my PrivateRoute component in case anyone was wondering:
const PrivateRoute = ({ component: Component, authed, ...rest }) => (
<Route { ...rest} render={(props) => authed ?
<Component {...props} /> :
<Redirect to={{pathname: '/'}} />
} />
)
What I've done so far:
- use componentWillMount() - no difference, plus I believe this will get deprecated soon
- use a global auth object which has an isAuthenticated, login(), and logout() members. I created an instance of that object in my Public component and added onClick={auth.login} along with the href. However, onClick runs first before href browser redirect, so it tries to fetch the user first (even though there isn't any set yet), so isAuthenticated doesn't get set to true
Thanks in advance!