Use React Native to post to secure AWS API Gateway endpoint

I am setting up a React Native application that will interface with an authenticated API hosted by AWS API Gateway. Here is how I set up my API to be secured through authentication. I am not sure that this will be used in production, but it is working well for testing.

This post will go over the following:

  1. Setting up a very simple React Native application
  2. Adding a simple button that will later be used to get data from an endpoint
  3. Using the react-native-dotenv module for environment set up
  4. Using the react-native-aws-signature module for authorization
  5. Debugging with react-native-aws-signature

Here is the code for this example on githhub

Setting up a very simple React Native application

Start with a brand new react-native application. To set one up, run:

You should get something in the simulator that looks like this:

Adding a simple button that will later be used to get data from an endpoint

In the index.ios.js file, add Button to the imports:

Replace the existing SampleProject Component with this:

Reloading in the simulator should give you something like this:

If you press the ‘API Request’ link, you should get this:

Using the react-native-dotenv module for environment set up

In a production mobile application, you don’t want to save secret API keys anywhere in the code because it can be reverse engineered. There is a SO post here about it.

That being said, if you are only installing the app on your phone during the testing phase, it is probably fine.

The official react-native-dotenv instructions are here, but this is what I did to set it up.

First, install the module

Add the react-native-dotenv preset to your .babelrc file at the project root.

Create a .env file in your project root directory with your AWS credentials and the host.

Now, let’s set up a really simple class that we will use to interface with our API. This should be at the same level as index.ios.js, and mine is called called SampleApi.js.

Then, somewhere near the top of index.ios.js, import the new class:

Replace the retrieveData function with:

Our full index.ios.js should now look like:

Note: if you change the .env file only, the simulator will not recognize the change and your changes will not take affect.

Using the react-native-aws-signature module for authorization

Now, we want to actually hit the API when the button is pressed. Start by installing the react-native-aws-signature module

In SampleApi.js, add the import for AWSSignature:

Remove the contents of the get() method in SampleApi.js and start by setting up some variables based on the .env file:

Next, set up the header and options. These will be used to generate the authorization details and they will be used in the request to the API.

Then, create a new AWSSignature object and call setParams. This will generate the authorization header, which we retrieve in the next bit of code:

Now, retrieve the authorization information and append it to our header.

Finally, make the request to the API using the header we just created. We are expecting json back, and I have included some basic error checking.

Here is what the SampleApi.js file should now look like:

Modify index.ios.js to set the state to include the return value of the request. Since we are getting a json array back, we have to loop through it to make a readable text block:

After you refresh the simulator, you should be able to press the button and receive a screen that looks something like this:

Debugging with react-native-aws-signature

This AWS troubleshooting guide is helpful, but react-native-aws-signature does most of the work for you, so it can be difficult to determine where your mistakes are.

I got this error when I was including the https:// at the beginning of the host parameter in the header. The full error includes what AWS was expecting for the ‘canonical string’ and the ‘string to sign’.

I figured out how to fix the issue by using the getCanonicalString() and getStringToSign() methods.