How To Implement OIDC Authentication with React Context API and React Router

Francisco Pastor
5 min readFeb 20, 2019

--

Hi readers, I’m writing this story to avoid more people going crazy trying to implement oidc client with react, have authorized routes and use the class provided by the library to manage all the needed behaviour in our react applications.

To give you an example, this is a boilerplate of create-react-app with the implementation.

Backend implementation is ready

First of all, this article is always going to talk about the frontend implementation. The identity server is currently implemented as this post of my partner Danny García Hernández explain in this story that you should follow.

What we are going to apply?

We are going to implement the behavior of the diagram:

  1. If a user tries to access a private route, the application is going to check if the user has been logged into the server, if authorized, we are going to allow the user access. If not we are going to redirect the user to the login screen to be logged and retry access to the private route.
  2. We are going to apply the mechanism needed to refresh the token of the user after an expiration time without the user realizing it.
  3. Finally, we are going to apply the behaviour needed in your register page to create users in our app.

Implementation

Install requirements

We are going to add to the project react-router-dom and oidc-client to our current project, in this case we are going to use a common create-react-app boilerplate to start

create-react-app oidc-react-app
yarn add react-router-dom oidc-client

Configuration files

First of all we are going to define the configuration needed to the oidc-client:

  • IDENTITY_CONFIG: The config needed to establish the connection.
  • METADATA_OIDC: The extra info that you want to have in the token.

On the wiki you can check the explanation of a better description for each parameter.

All the environment variables should be added to the .env files, these variables should be provided by the backend and match with the configuration of the server.

Create the authService

To manage the object provided by oidc we are going to create a class that is going to instance the object and is going to store the UserManager provided by the library. In this class we are going to create the methods to manage the user authentication and authorization flow.

It’s important to think of the implementation in line 19 over the event raised by the library “addUserLoaded” that is going to control the flow and only in the case that the user comes from the login redirect url we are going to redirect the user to the principal private screen, allowing the event to renew the token with the silent renew mechanism.

Create UserContext

Now we have our class to manage the UserManager object. We are going to need one instance of this object in different places in our app, for example in the register page or in our private routes to validate if the user is allowed to access the route.

The library said it is prepared to be instanced multiple times and itself is going to check if another object is currently created, but for better organization of the code and to be sure to instance it only one time we are going to use the Context API of React.

So we are going to create the AuthContext, the AuthProvider with the instance of our AuthService and the AuthConsumer to be used in our application.

With that we achieve having our AuthContext the AuthService instanced, and if we need it we have it in the AuthConsumer.

Prepare the components to be used on routes

On this point we have the possibility to start to create consumers in our components, we are going to create the components first and define the routes after.

  • PrivateRoute: this component validates the user access, if the user is not authenticated they will be redirected to the login screen and after will come back to the requested route.

Some components are needed to manage the user flow, these components execute different functions of AuthConsumer and they are going to be accessible by route.

  • callback: This component is going to be used after login when the user is going to be redirected by the server to the redirect_uri setted on the IDENTITY_CONFIG
  • logout: This component is going to logout the user.
  • logoutCallback: After logout the server is going to redirect the user to the post_logout_redirect_uri property of the IDENTITY_CONFIG where the logoutCallback is going to delete the cookie from the identity server and the localStorage cleaning the browser, and redirect the user to the REACT_APP_PUBLIC_URL defined in our .env file
  • silentRenew: Is going to be used by the event addAccessTokenExpired configured on the AuthService.

Create our router

Now that we have all the components needed we are going to set up our router. In our routes file we are going to create the routes and the components associated to each route.

As you can see we are not creating a login screen or anything similar. In the backend the identity server side implements its own login and register screen by default, we are going to use these screens to register a new user and to be logged into the identity.

If you want to manage the register and the login you can implement both your react app, creating the route directly in the routes.js file and managing the forms inside the app.

Render all in our App

We have all the components and configurations done. We are going to use BrowserRouter with our routes config file, and we are going to pass it as children of our AuthProvider that is going to give access to the components to the consumer.

Everything should work

At this point if we have all the url’s working and our authConst configured all the mechanisms should work as specified in the diagram.

In this post, we saw how to implement oidc with react and react-router by an implementation of React Context API, I hope you enjoy the behaviour and if you have any questions regarding this or anything I should add, correct or remove, feel free to comment.

Thanks !!!

--

--