Have you read the react-router-v4 documentation that explains redirects with special emphasis on auth? That is the method I have used in the past and it's worked really well.
The gist is that you create a <PrivateRoute /> component that wraps react-router's <Route /> component and basically will display the Login component if the user tries to navigate to a private route without being logged in. Otherwise the user will be given the view for the route that they requested.
For example:
<BrowserRouter>
<Switch>
<Route path="/" component={LandingPage} />
<PrivateRoute path="/main" component={ContainerSingleApp} />
<Route component={Error} />
</Switch>
</BrowserRouter>
And from the documentation:
function PrivateRoute({ component: Component, ...rest }) {
return (
<Route
{...rest}
render={props =>
fakeAuth.isAuthenticated ? (
<Component {...props} />
) : (
<Redirect
to={{
pathname: "/login",
state: { from: props.location }
}}
/>
)
}
/>
);
}
To solve the problem of having the user press the back button you can swap out the redirect in the PrivateRoute component with your Login component. That way you aren't actually doing a redirect to a route that points at your Login, you are simply rendering the Login in place of the private component that the user is trying to access. Once the user is logged in, it will render the component that they are trying to see. Since there is no /login route needed for this approach, you don't need to worry about the user browsing back to the login page unless they are actually not logged in. See the changes in the code below:
function PrivateRoute({ component: Component, ...rest }) {
return (
<Route
{...rest}
render={props =>
fakeAuth.isAuthenticated ? (
<Component {...props} />
) : (
<Login />
)
}
/>
);
}
The routes in the first coding example above demonstrate a setup where the landing page is not protected by authentication.
If you want your landing page to be a view that is protected with authentication (like your /main route that points at the ContainerSingleApp component) then you still wouldn't need to add the Login component as a route. You could do something like this:
<BrowserRouter>
<Switch>
<PrivateRoute path="/" component={ContainerSingleApp} />
<Route component={Error} />
</Switch>
</BrowserRouter>
Remember that in the PrivateRoute component it will display the login view automatically if the user isn't logged in. If they are, it will render the passed-in component.
It's important to note that the url will never show something like https://your-site.com/login. It will always show the route for the component the user is attempting to access. The difference being that the component that it renders will depend on whether the user is authenticated... The Login component if not, and the ContainerSingleApp component (or whatever component that route points to) if logged in.
If you still want to create a route to the login page you can use a redirect:
<BrowserRouter>
<Switch>
<PrivateRoute path="/" component={ContainerSingleApp} />
<Route path="/signin" component={() => <Redirect to="/"/>}
<Route path="/signup" component={Signup} />
<Route component={Error} />
</Switch>
</BrowserRouter>
See the redirect documentation. As for the Signup component... Just add logic in it that will redirect the user to another page if already logged in. You can use a similar approach that you used with the PrivateRoute component.