So, this might be a slightly lengthy answer -- but you've posted a rather interesting and important question.
As someone who spends a majority of my time writing security libraries in Node and Python to handle this exact sort of thing, I figured I'd jump in here.
The protocol you want to use to protect your React app and backend API is the OAuth2 Password Grant flow. The way it works in theory is quite simple.
On your React app, you collect a user's username/password (this could also be an email/password if that's how you've structured your application).
You then send a POST request to your backend API that looks something like this:
POST api.myapp.com/oauth/token
grant_type=password&username=USERNAME&password=PASSWORD
Make sure you use the application/x-www-form-urlencoded
content type when posting to your server.
Your server will then take this request, run it through an OAuth2 library, and generate two tokens: and Access and Refresh token.
Once you've got the tokens generated on your server side API, you'll then store those tokens in a cookie which will then be stored by the user's browser.
From this point on: everything should be automatic. When your React server makes API requests to your backend, the browser will identify the user via that cookie containing those two tokens automatically.
You'll need to use an OAuth2 library for your server-side, as this will handle things like:
- Generating tokens.
- Exchanging a Refresh token for a new Access token when it expires.
- Identifying the user based on the tokens.
- Revoking tokens if they are compromised, etc.
There's quite a lot more to it, but this is the basic, high level idea.
As you'll notice: there are no API keys involved here. When you're working with untrusted environments (eg: mobile apps, or client side javascript apps) it is completely unsafe to store permanent API tokens -- the reason is that they can be easily extracted from source code, or javascript.
Using the flow mentioned above instead is much safer, as you get a lot of protection:
- No permanent credentials stored in an unsafe location.
- Short-lived tokens are used as identifiers. These are rotated over time.
- Tokens are stored in cookies that are NOT accessible to Javascript. This means less risk of web exposure.
- Password are only exchanged once, for the duration of a session -- this means less sensitive information is going over wire less frequently =)
Anyhow: hope this helps!
And, if you're looking for some tools, any oauth library (server-side) should help you with this stuff. If you're looking for a service that can do this for you, you might want to check out the product I work on (Stormpath). It's a paid service, but handles a lot of this complexity on your behalf.