How to implement authentication in ReactJS
The word authentication is familiar in the Digital field. Developers throw around this word frequently when implementing security for any website. What does it mean??
Authentication
Authentication is verifying the identity of people while restricting certain features and access to some web pages based on the user type classifications.
Usually associating all users with a unique identifier which can be a username or userID is a normal procedure. A common practice to authenticate users is to combine username and password. We have many types of authentication which we’ll discuss shortly. But first, let’s see what are the distinct ways to authenticate. We can implement many authentication methods for your front-end application
Basic HTTP Authentication: This is the simplest method where a client makes a request to the server with the relevant username and password. The client sends an Authorization header along with every request which comprises non-encrypted username and password. Instead, we can concatenate them into a string like username:password and encode it to Base64. Adding a ‘Basic’ keyword before the encoded string will help the server identify this request.
Example request: curl –header “Authorization: Basic am9objpzZWNyZXQ=” my-website.com
Cons:
- There is a higher risk of exposing the username and password with each request.
- No way to log the user out with this method
- Username and password can get exposed immediately if there is weak encryption or an attack on the website because of the SSL/TLS connection.
Tokens: JWT (JSON Web Token) is a popular and less risky authentication method. A JWT token consists of 3 parts
- Header that contains the token and hashing algorithm.
- Payload made up of verifiable security statements.
- Signature created with Base64 encoded header and payload with a secret key signed off with the hashing algorithm mentioned in the header
Example token if you are using HMAC SHA256 hashing
HMACSHA256(
base64UrlEncode(header) + “.” +
base64UrlEncode(payload),
secret)
Cons: Easily Susceptible to XSS attacks.
Also Read: Fundamentals of ReactJs
OneTime Passwords: Applications that require two-step verification can use this method to authenticate. The algorithms generate OTP with a shared secret key + current time or a counter. Here a user enters the username and password and both server and client work together to generate an OTP.
Cons:
- If someone steals the shared secret, they can imitate the user tokens.
- Added risks from password reset feature because clients can go wrong.
Obstructing access to some features of the application is a common use-case on web applications. Authentication is the most crucial part while building a stable product. SPA (Single Page Application) pattern and Reactjs will have to deal with authentication both from the API side and front-end. Let’s discuss the basic authentication ways with ReactJS.
Preventing render of a component through the link: The first authentication method is a simple conditional statement to prevent the component you are trying to access from rendering.
function BusinessComponent({ user })
{
return ( | |
<div> | |
{user && <h1>Welcome ${user.name}</h1>} | |
</div> | |
); | |
} |
As the number of conditions increases, the code will become messy. Solve this can by adding a simple wrapper to your component that will check the condition for you.
function Protected({ user, children }) { | |
if (!user) { | |
return null; | |
} | |
return children; | |
} | |
function BusinessComponent({ user }) { | |
return ( | |
<div> | |
<Protected user={user}> | |
<h1>Welcome ${user.name}</h1> | |
</Protected> | |
</div> | |
); | |
} |
This is a straightforward way of rendering children of the component. But with this approach, the child gets compiled even though there is no rendering, also if the condition fails you cannot render anything else.
To handle these two drawbacks, we can use React RenderProps
function Protected({ user, render, fail }) { | |
if (!user) { | |
if (fail) { | |
return fail(); | |
} | |
return null; | |
} | |
return render(); | |
} | |
function YourComponent({ user }) { | |
return ( | |
<div> | |
<Protected | |
user={user} | |
render={() => (<h1>Welcome ${user.name}</h1>)} | |
fail={() => (<a href=”/signin”>Signin</a></Protected>)} | |
/> | |
</div> | |
); | |
} |
RenderProps pattern lets you show and hide content to the users based on the existence of the user record in your database. Connect the <Protected> component to redux to make it better for retrieving user information and improving conditions that check permissions
import { connect } from ‘react-redux’; | |
import PropTypes from ‘prop-types’; | |
import { hasPermissionTo } from ‘helpers/Permissions’; | |
function ProtectedComponent({ user, permissions, render, fail }) { | |
if (!hasPermissionTo(permissions, user)) { | |
if (fail) { | |
return fail(); | |
} | |
return null; | |
} | |
return render(); | |
} | |
ProtectedComponent.propTypes = { | |
fail: PropTypes.func, | |
render: PropTypes.func.isRequired, | |
permissions: PropTypes.oneOfType([ | |
PropTypes.string, | |
PropTypes.arrayOf(PropTypes.string), | |
]), | |
user: PropTypes.shape({}), | |
}; | |
export default connect(state => ({ user: state.user }))(ProtectedComponent); |
Stop Route from being accessible:
The second authentication method is blocking access to the route. Using <Switch> component is common if you are using the common react-router for routing. <Switch /> component must have children like <Route /> or a <Redirect /> and so using <Protected/> component is not an option here.
function getProtectedRoute(path, component, user, permissions) { | |
if (!hasPermissionTo(permissions, user)) { | |
return <Redirect exact path={path} to=”/forbidden”} />; | |
} | |
return <Route exact path={path} component={component} />; | |
} | |
function AppRouter({ user, history }) { | |
return ( | |
<Router history={history}> | |
<Switch> | |
<Route exact path=”/” component={Home} /> | |
<Route exact path=”/forbidden” component={Forbidden} /> | |
{getProtectedRoute(“/admin”, Admin, user, “administration”)} | |
</Switch> | |
</Router> | |
); | |
} |
Here the wrapper function getProtectedRoute will check for the user permissions and if the user tries to access the ‘/admin’ route without logging in, this function will directly return the ‘forbidden’ page. The component has not complied as we block access to the routes that require authentication.
Conclusion:
These are some of the simplest ways of providing authentication and protecting the user data from threats via front-end coding. In case you have complex applications with many shared screens between authenticated and unauthenticated users, you can go for Reactjs latest hooks and context that also make front-end authentication simple.
Tag:authentication, javascript, React, reactjs