If this is for native apps, you can try the following,
- Store an access key in your app bundle. Nobody other than app owner (yourself) can have this.
- Change your API so that only requests with the access key set in header will succeed.
- Use HTTPS so that nobody can read the encrypted access key.
If you don’t use HTTPS, you can still manually hash the access key with something in the header (only your server and app logic knows how) so that man in the middle can’t pretend to be your app.
If this is for pure web apps,
I would first suggest wrapping the pure web app inside a native app (a.k.a. Hybrid app) so that you can achieve the protection outlined above, by bundling a secret key inside the app. Developing a native app with a single web view inside shouldn't cost too much.
However, if that is not possible, so your app remains a pure web app - here is a potential option,
- When server serves the web app, supply an access key.
- When the web app makes API call it needs to supply a hashed version of the access key.
- How your web app hashes depends on logic that are implemented in minified+obfuscated codes.
- Your backend API then validate the hash by applying the same hidden logic to the stored access key to calculate the hash and see if it matches.
- You can change the hidden logic and access key as frequent as needed to reduce the chance of someone getting the right hash.
This is of course not bullet-proof but as you know, there is no perfect security and this probably achieves the purpose (and hopefully fits the bill). I would say going hybrid is more cost-effective though.