11

I'm trying to create a website using react+redux. I've already setup jwt authentication on the server. What I'd like to do is to lazy load some of my components/containers and reducers so that they can be downloaded only by authenticated users. I already know how to hide components from unauthenticated users (client side), but I would prefer to prevent them from downloading the relative javascript code.

I am using webpack, and I've already looked into react-router and require-ensure (https://stackoverflow.com/a/33044701/2920112), but this approach doesn't seem to handle authentication at all. I've also considered using fetch in some way (probably bundling the private code separately with webpack), but I wouldn't know what to do with the bundle once I fetch it.

Am I approaching the problem in the wrong way? The only alternative I see is to provide two HTML files, one loading a webpack bundle with only the public content, and one downloading also the private code. This however seems really suboptimal. What is the correct approach?

Community
  • 1
  • 1
lgpasquale
  • 486
  • 4
  • 8
  • I believe you can use `require-ensure`, you just need to include your own authentication logic. The user authentication changes what you call with `require.ensure()` and what component you'll pass to `cb` callback. – Lucas Feb 22 '17 at 22:31
  • Have you found a solution? I'm facing a similar issue. All assets are protected and require a token in the request header. Not sure how to hijack whatever require.insure does in the background so that it sends the token when downloading the next chunk. – Tamás Apr 30 '17 at 19:53
  • Maybe you can use [dynamic expressions in a dynamic import](https://webpack.js.org/api/module-methods/#dynamic-expressions-in-import) to include an API token that could then be parsed by an http server to pull out the token from the url and only serve the file if you're authenticated. Something like `import(\`./secure/${token}-file.js\`)`. – redbmk Mar 13 '20 at 16:52

2 Answers2

1

We solved this by using react-router:

<Route 
    key="secured_component" 
    path="/secured" 
    onEnter={handleEnterSecuredComponent}
    getComponent=({nextState, cb) => {
       require.ensure([], () => {
           cb(null, require('YourComponent').default);
       });
    }}
/>
...
const handleEnterSecuredComponent = (nextState, replace) => {
    const {login: {success}} = store.getState();
    if (!success) {
       replace('/login');
    }
};

So your login page should set in redux {login: {success: true}} if user is authenticated. If an authenticated user tries to access /secured, he will be redirected to /login.

the require.ensure does not play any role of authentication. It just an entry point for webpack to split the chunk of js files for lazy loading.

tenolife.com
  • 326
  • 2
  • 8
  • 2
    I'm already doing something similar (with react-router), but this doesn't prevent an unauthenticated user from loading the sensible javascript code if he wanted to. If he manually submitted a GET request to the URL of the chunk created by webpack through `require.ensure`, there would be no authorization mechanism to prevent him from downloading it. – lgpasquale May 02 '17 at 07:54
  • 3
    @lgpasquale: Javascript in the frontend shouldn't contain sensible code at all… Never trust the client! All "real" security mechanisms you implement should be server side only. Everything else is just for the UX. – sclausen Jul 10 '17 at 12:09
0

For anyone still looking into this, React has now added the ability to split the codeand do lazy-loading when using webpack:

https://reactjs.org/docs/code-splitting.html

While this by itself is not enough to require authentication for the lazy-loaded modules, it can be paired with some authorization mechanism living on a reverse-proxy.

lgpasquale
  • 486
  • 4
  • 8