In this article, we are going to learn how to setup user authentication with role based access in React applications.
tl;dr If you are impatient and want to go straight to the code, here is a link to the application with auth flow set up 😀
Global session container
First, let’s create the state container in order to keep the information regarding user authentication session globally.
Session state will be stored inside of React context, so we could access it before rendering of any page and make a decision whether the user is allowed to access it.
Once user logs in the application, we call
createSession function, which will change
isAuthenticated state to
true to update the app accordingly. Along with setting state locally, we also keeping it in sync with local storage, to keep user authenticated across page reloads.
Note, we keep
isAuthenticatedflag instead of authentication token in the local storage in order not to be vulnerable to XSS attacks. That requires authentication token to be set via
httpOnlycookies by a back-end server.
Along with keeping authentication state, we also set
data variable for storing authorization data such as user role or his progress of the onboarding. That variable will tell us in the future which pages user is allowed to visit in our application.
Every application page will be wrapped into a
Page component, which will load user data upon mounting and making a decision whether to grant or decline access depending on the user response.
Here, we are using the conception of
guards, which essentially are simple functions taking
isAuthenticated variable and user personal data as input and returning boolean value which indicates whether the user is allowed to access specific page. Depending on the application, there could be multiple guards for example, for unauthenticated users (which will allow access only to the sign in and sign up pages), onboarding users (will allow access to the onboarding frames but not the complete application), authenticated users (which will allow the access to the rest application)
Once guard denies an access to the page, we should do a redirect. The interesting point is, that depending on the user state we do different redirects. That’s what
redirectTo function is responsible for. When signed out user tries to access the main page, it’s good to redirect him to the sign in page. When authenticated user accesses sign in page, which should move him back to the main application frame. When the user who not finished setting up his profile opens main page, we should move him to the profile setting page and so on.
Under the hood of
Page component, at the first point we make our guard check across the signed out users, in the success case when guard approves without user data, we render page content, otherwise we do appropriate redirect.
If after all our guard still remains failed, we have to load the user personal data which will allow us to repeat guard check but with user data provided. That’s what
Authenticated component is responsible for, which has similar logic to the main
Page component in addition to fetching the user data itself.
Finally if guards give us a green light - we’re good to render page content.
Integration with router
In this example we’ll be using
@reach/router but a similar flow could be applied to the
react-router or similar libraries.
In the place when we define our application routes, we have to wrap every component into a
Page and providing a guard(if needed). In that case once the needed route loads, at the first point the logic of the page component will be executed and depending on access user will be either shown the content of the page or made a redirect to the allowed location.
Real world application
In order to have a full picture of the flow, it’s good to illustrate that approach on a real-world scenario.
In our case we’ll have an application with the following pages:
- Sign in. After success authentication, depending on whether the user set up his profile or not, he will be redirected either on the profile setup or main application page.
- Profile setup. Frame for the users who didn’t finished the profile setup flow.
- Main page. Frame where regular application users are living.
Here is the working example illustrating the complete flow described above.