Securing React Redux Application — Public & Private Routes
Let’s say we are building a web application and we have multiple Users and Roles, Every user and role has his own “Data Domain” which he can view and navigate to.
To implement this approach in a Client-Server application, generally, we will design a Server which will have the ability to restrict access to the service APIs for the application’s users and security roles.
When the client requests any data from the server, the server will check the user’s credentials and acts accordingly.
Lets look at an example in a stateless and RESTful manner:
fetch('htpp://localhost:5000/', {
method: 'POST',
cache: 'no-cache',
headers: {
'Content-Type': 'application/json',
'Authorization': 'some-token',
},
body: {},
})
For example we can send an Authorization header to pass to the server the credentials of the user in order to check for role and authentication.
There are many different ways we can design Security, but for this article let us focus on the client-side, and how we can secure pieces of code or different components or pages based on credentials and roles.
To complete and improve this “Security Layer” we will add additional sub-layer and check for authentication and roles also (if roles data available on the front-end) in the client by wrapping our routes into some logic to check whether to continue to that route or to redirect to another route based on the logic.
1. Defining Routes
function PublicRoute({ component: Component, isAuthenticated, ...children }) {
return (
<Route
render={props =>
isAuthenticated ? (
<Redirect to="/" />
) : (
<Component {...props} {...children} />
)
}
/>
);
}
export default PublicRoute;
function PrivateRoute({ component: Component, isAuthenticated, ...children }) {
if (isAuthenticated === true) {
return <Route {...children} render={props => <Component {...props} />} />;
}
return <Redirect to="login" />;
}
export default PrivateRoute;
Let’s see what we did here:
First of all we are using Stateless React component since we are not using any state logic, and we are using react-router-dom and ‘Switch’.
PublicRoute is the route we use for public access(unauthenticated users) e.g. Login page (“/login”) or Register page (“/register”), where we are not checking for authentication and roles data.
PrivateRoute is the route we use for private access(authenticated users) e.g. Dashboard page or My Profile page. When PrivateRoute gets unathenticated user it automatically redirects the user to the Home Page (“/”)
2. Building our Router
render() {
const { isAuthenticated, roles } = this.props;
return (
<Switch>
<PublicRoute
exact
isAuthenticated={isAuthenticated}
roles={roles}
path="/"
component={Home}
/>
<PublicRoute
exact
isAuthenticated={isAuthenticated}
roles={roles}
path="/login"
component={Login}
/>
<PrivateRoute
exact
path="/dashboard"
component={Dashboard}
isAuthenticated={isAuthenticated}
roles={roles}
/>
<PrivateRoute
exact
path="/profile"
component={Profile}
isAuthenticated={isAuthenticated}
roles={roles}
/>
</Switch>
);
}
We design a <Swicth> by ‘react-router-dom’ that will use our Routes that we defined early.
You can extend the Routes and pass to the function any further logic as we need, like roles.
This security new added layer is not the application main security, it is only UI/UX improvement to make a good behavior, consistent UI and to avoid getting broken screens when getting Unauthenticated or Unauthorized errors.
To fully secure our application we should provide a good security on the server side, so we can block and restrict malicious and unwanted requests to the services from users.