manuelbieh / react-ssr-setup

React Starter Project with Webpack 4, Babel 7, TypeScript, CSS Modules, Server Side Rendering, i18n and some more niceties

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Problem with rendering of Authenticated routes and Non authenticated routes

NileshTops opened this issue · comments

Hi, Can you please tell me how can i implement Authenticated routes and Non authenticated routes with react-router in this repository?

Hi! I was asking the same question a while ago. Despite the fact that @manuelbieh gave me a quick and detailed response #100 I did follow his advice, but modified it for my purposes.

So you don't want to render a cheap login page for an authenticated user to request later a heavy main page with all them fancy images, large bundles and texts, right?

There 2 main things in my solution that really helped me out, which are http-only cookies and separation of authentication and routing.

Firstly, usage of http-only cookie shifts the weight of storing a user ID in webstorage, accessing its value on the client, protecting it from CRSF and sending it with each request from your shoulders onto the browser's. Browser will send it every time he sees your origin in the URL.

Secondly, routing needs to do only one thing in your app, respond to the path change in the URL and bring a user to a necessary page, depending on the state of the app. So there is no need to create something similar to react-router's private routes, but the logic stays the same - there are public routes and there are private routes.

So, provided a browser is using a http-only cookie, you don't have to worry about the initial request to your server, which will be for index.html (I suppose any proxy server in your network allows the request to reach the node server, which will SSR your page into a html file). You will always receive information about the user, because browser will send a token - user ID preserved in browser's internals. You will either receive it - that tells you user is authenticated and it is ok to let him through or he needs to update his expired token, OR you will not (your server didn't previously set a unique ID for this user, or the user cleared his browser internal storage).

The solution is rather simple, the store must have information about the user before being created. Thus, you need to check for the presence of a cookie, its value (it can be expired) and initialise the store with some initial state of the app, let's say, "profileType" of the user, which can be 'authenticated', 'unauthenticated' or better an empty string '', 'expired' and so forth.

Going further, there are two basic scenarios - authenticated and not authenticated user. Both of them are allowed to access a requested URL, but what will be returned in response differs and depends on the "profileType" in the store.

What you need is a HOC (well, it is not a pure HOF, but let's call it HOC) for each container (except the one where routing happens - App.js) that will act like an interceptor in express.
My example looks like this (I can show you only its API):


/**
 * auth is a HOC that checks provided conditions on mount and on nextUpdate
 * It receives 3 function arguments
 * @param {function} meetCondition - verify user identity
 * @param {function}  damnGoBack - function that is called when the condition above is not met (it can be redirect to login page or any other page or just a notifier)
 * @param {function} whenToCheck - due to the fact that it is HOC, any props change is registered. So you can tune when you want meetCondition to be invoked. (used in CDM(), CDUP() etc)
 */
const withAuth = auth(
  ({profileType}) => profileType !== 'unauthenticated',
  ({some props you need}) => customFunction(with those props),
  (nextProps, props) => nextProps.profileType !== props.profileType
)

withAuth(YourContainer)

Before rendering a component provided for a certain route it will check for your provided condition to be met and either grant access to the container OR do whatever you want it to do, in your case redirect to the login page to let the user proceed with authentication process.

This HOC allows you to follow flux architecture (the View changes based on the changes in the global state) and react on API request interceptors that require token to let the request knock on your DB door. If server API interceptor returns 'expired' or 'unauthenticated' (logged out in another open tab), this HOC will know it first.

There is yet a lot to mention, but I hope you got my idea and wish you to solve your problem)