Consider splitting your React application into several SPAs. Each SPA is rendered by its own script bundle. For example you can have Login SPA rendered by login.js
bundle and the rest of the application catered for by the App SPA rendered by app.js
bundle.
The first bundle would allow users to login. After that their identity is established and the payment status is retrieved from a database. The link to the next webpage with the paid-only functionality will be conditionally shown to paid users, otherwise the link will be hidden but still easily discoverable by inspecting HTML via Page Source browser's menu.
Following this link will make the webrowser load the second SPA which calls the API endpoints for the paid users and contains webpages restricted to the subscription.
Are there any methods to prevent(or harden the ability to remove certain restrictions/api calls etc) users to access the app without paying?
The webserver will refuse to serve the app.js
bundle in case of a non-paying user.
As a practical example of a React app split into two SPAs with two script bundles see demo website and the Crisp React solution. The demo does not make the second bundle download conditional but this functionality can be easily added.
P.S.
@winwiz1, do you mind to explain how is this different than splitting the code with protected routes?
I assume it's about the difference between obfuscation and bundle/URL rotation.
Obfuscation
Doing it once is not a reasonable option. Someone can customize an existing deobfuscator or write a custom one and post a hack on some forum. You can keep changing the obfuscation technique. If you do it cheaply (for example change the constant used to XOR the ‘protected’ code), then a decent deobfuscator embedded into a hack can pick it up automatically. If you do it in-depth then continuing doing it over and over again would be expensive and likely not a viable option.
Bundle/URL rotation
Financial institutions exchange nightly batch transactions using encryption with complimentary hardening achieved by making URLs non-public. And they enhance security by rotating encryption keys. In your case the URL is public so you could achieve/enhance hardening by rotating URLs.
For this to work, the client-side caching of the HTML (that contains references to the script bundles) will have to be disabled, as is the case with the demo website and the solution mentioned above. The solution already uses bundle names that include hashes and generates HTML automatically. The only outstanding task would be to rotate URLs by inserting some GUID into it.
The difference
The difference will become obvious if you try to estimate the costs (time and efforts) required to implement obfuscation vs bundle/URL rotation, though this requires a good grasp of both approaches. The next step would be to pretend to be a hacker and consider the practical solutions aimed at defeating obfuscation or bundle/URL rotation. For each solution consider the implementation with related complexity, costs and risks. Which would obviously depend among other things on the method of supplying the non-paid users with the hack, whether it’s once off posting to an underground forum or requires to additionally have continuing online presence - to keep logging in to get new bundles with rotated URLs, to keep making these available to non-paid user base via some online notification mechanism utilised by the distributed hack etc.
The whole issue is about authentication (and getting user identity with payment status) folowed by authorization (whether to expose some functionality or not). As already noted by others, it's a wrong approach to try to enforce either on the client side. The enforcement should be on the server side complimented by additional security measures on both sides because good security is always multilayered.