This is a frequently asked question that doesn't get the attention that it probably deserves, until now:
"How can I be sure that an incoming HTTP request was generated by a specific app?"
Some variant of this question comes up quite frequently. Every hyperlinked word in the preceding sentence is a distinct StackOverflow question from 2016 that is looking for the same solution.
The solution you're searching for does not exist.
If you ever find yourself needing to guarantee that your authorized client-side code is the only application capable of sending messages to your server in order to be secure, step back and re-assess the situation.
Ask yourself: Why exactly do you need this guarantee in order for your server to be secure? What is it that you're doing, server-side, that makes it mission-critical that this client only be allowed to behave in a way you've pre-ordained in your engineering designs?
You're trying to solve the wrong problem.
One of the most basic rules of application security is input validation. The reason this rule is so fundamental is because your server only has control (and visibility) over the software running on itself. Every other device on the Internet is a black box that you can communicate with over networking protocols. You can't see what it's doing, you only see the messages that it sends.
You can't verify that the client is running your approved software. Similarly, clients cannot prove that the server is behaving honestly either. (Similarly: VPN services that market themselves as privacy solutions should not be trusted.)
"But I have a clever solution. It involves cryptography."
Cryptography is a wonderful way to send messages over a hostile network without losing confidentiality or integrity. However, cryptography does nothing to stop reverse engineers: Your computer has to be able to decrypt your program in order to run it. Physical access trumps anything you can throw at the user.
"What about DRM? That's effective, right?"
If DRM (Digital Restrictions Management) is ever effective, it is only so because of legal threats, not on its own technical merits.
What is the right problem to solve?
The server should remain agnostic to the client.
The software on the client and the software on the server should have a mutual distrust towards each other. Any messages that the server receives should be validated for correctness and handled with care. Data should never be mixed with code if you can help it. We've covered this before.
A well-designed server-side API, from a security engineering perspective, isn't one that falls over the moment someone clones your client-side app and modifies it to behave maliciously; it's one that remains secure even when the client is malicious.
Even if you could wave a magic wand (say: quantum cryptography) and say, "Yes, only our approved client can communicate with our server," what's stopping a mistake in your server-side code from being permitted in your client-side code? After all: If you're not even aware of that a vulnerability is possible, what's to stop you from allowing it in two places?
When you stop and think about it, it doesn't really make sense to even try to solve this problem. It makes even less sense when you weigh these desires against the desires of computer users to maintain autonomy and freedom over their own devices.
The take-away is: Instead of trying to control your users, focus on making their misbehavior inconsequential to the stability and integrity of your server.