Shrouk Khan
Shrouk Khan

Reputation: 1460

React-native / AWS API Gateway android issue

I am trying to use react-native with aws api gateway. Same code ( pure JS ) works great on ios but on android it fails with 403 error.

var signedRequest={
  "headers": {
    "Content-Type": "application/json",
    "Accept": "application/json",
    "x-amz-date": "20170918T134411Z",
    "Authorization": "AWS4-HMAC-SHA256 Credential=ASIAIBC7RQ7MFUIRO7QQ/20170918/ap-northeast-1/execute-api/aws4_request, SignedHeaders=accept;content-type;host;x-amz-date, Signature=9fb6d4d4820024097f25aaa70648fxxx7a54a2db1a67d173189693dc073d0a0bac8",
    "x-amz-security-token": "AgoGb3JpZ2luEKn////////xxxG1iKJBHjjvZH0DxcSqE889Wb3Mv+8PwMqrRe/O5dFFmP+9bQj+fSwVIUvmBplKkQB62x/xTelGHoCEOPXpBWLjT2OAUaBXOti7UZyfyMNgg56/Z58yxk4o2/37xPLbhXfODaL8kydFV8IaPJjdbJIX+a0kXycPLBnVIBdukUp9cMVD27mWN41u3w0VP5J8YiMPzrDnwKtb0U37naoIaknMBqNBDkMGQyHal/TBJ3wjJvJWVntrJvex0QKD8rDLHjaoiIYjBd+a04m2pKsBQJ9WQl02TTCPgRp0bb1oARF2hz0Xpi45Ba6a6E9SAL07UcRShTwX6rmxi0dZ38mkSbBMjI45Xg8r/VaRZx6/OyCq3u+nq4bgLCOMKqb/80F"
  },
  "data": "{\"data\":{\"func\":\"checkIfFacebookSignupComplete\",\"data\":{}}}",
  "method": "POST",
  "url": "https://xxx.execute-api.ap-northeast-1.amazonaws.com/dev/user/user"
}

var apiResponse=await fetch(signedRequest.url, {

  method: signedRequest.method,
  body: signedRequest.data,
  headers: signedRequest.headers,

})
console.log("Got api response : ", apiResponse)

On iOS it receives a http response 200. However, on android it fails with:

"The request signature we calculated does not match the signature you provided. Check your AWS Secret Access Key and signing method. Consult the service documentation for details.

The Canonical String for this request should have been
'POST
/dev/user/user

accept:application/json
content-type:application/json; charset=utf-8
host:uihw7hnkn7.execute-api.ap-northeast-1.amazonaws.com
x-amz-date:20170918T134411Z

accept;content-type;host;x-amz-date
6b83b80f2875c2425c28b258886ad98603fd802095e35303a3c2a72528374fb5'

The String-to-Sign should have been
'AWS4-HMAC-SHA256
20170918T134411Z
20170918/ap-northeast-1/execute-api/aws4_request
008853cdfba53255257d9169e1a9c05500d01299da9efd4695ac8c66cb31e5e7'
"

I have tried axios as well . and same result. ( ios works fine, android fails ) I am using react-native 0.42.3.

Anyone got any idea what might be the issue?

Upvotes: 4

Views: 1352

Answers (3)

tomatentobi
tomatentobi

Reputation: 3157

I was fighting with the same issue. GET worked on both platforms, but POST only on iOS. Setting Content-Type to "application/json; charset=utf-8" before signing the request with sigV4Client fixed it for me.

const path = 'https://your-aws-endpoint.com';
const method = 'POST';
const queryParams = {};
const body = {};
const headers = {
    'Content-Type' = 'application/json; charset=utf-8';
};

const client = sigV4Client.newClient({
    accessKey: ACCESS_KEY,
    secretKey: SECRET_ACCESS_KEY,
    sessionToken: SESSION_TOKEN,
    region: REGION,
    endpoint: ENDPOINT,
});

const signedRequest = client.signRequest({
    method: method,
    path: path,
    headers: headers,
    queryParams: queryParams,
    body: body
});

fetch(signedRequest.url, {
    method: method,
    headers: signedRequest.headers,
    body: JSON.stringify(body)
}).then((results) => {
    ...
});

Upvotes: 1

Richard
Richard

Reputation: 1780

The new AWS Amplify library (https://github.com/aws/aws-amplify) on the official AWS repo has support for automatic signing to API Gateway. This is part of the API module: https://github.com/aws/aws-amplify/blob/master/media/api_guide.md

You would first install the React Native npm module:

npm install aws-amplify-react-native

Then link the project: https://github.com/aws/aws-amplify/blob/master/media/quick_start.md#react-native-development

After that you can configure APIs:

import Amplify, { API } from 'aws-amplify';
Amplify.configure(
    Auth: {
        identityPoolId: 'XX-XXXX-X:XXXXXXXX-XXXX-1234-abcd-1234567890ab',     //REQUIRED - Amazon Cognito Identity Pool ID
        region: 'XX-XXXX-X', // REQUIRED - Amazon Cognito Region
        userPoolId: 'XX-XXXX-X_abcd1234', //OPTIONAL - Amazon Cognito User Pool ID
        userPoolWebClientId: 'XX-XXXX-X_abcd1234', //OPTIONAL - Amazon Cognito Web Client ID
    },
    API: {
        endpoints: [
            {
                name: "ApiName1",
                endpoint: "https://1234567890-abcdefgh.amazonaws.com"
            },
            {
                name: "ApiName2",
                endpoint: "https://1234567890-abcdefghijkl.amazonaws.com"
            }
        ]
    }
});

Following that your API Gateway requests are signed using the user's credentials:

let apiName = 'MyApiName';
let path = '/path'; 
let myInit = { // OPTIONAL
    headers: {} // OPTIONAL
}
API.get(apiName, path, myInit).then(response => {
    // Add your code here
});

Upvotes: 1

Shrouk Khan
Shrouk Khan

Reputation: 1460

After digging around a lot it appears the issue is related to as described here: https://github.com/facebook/react-native/issues/14445 . android okHttp library ( inernally used by react-native ) added charset=utf=8 to the request. So the solution is to calculate sig4 value with header like this:

  var signedRequest={
  "headers": {
    "Content-Type": "pplication/json; charset=utf-8",
    "Accept": "application/json",
    "x-amz-date": "20170918T134411Z",
    "Authorization": "Calculated sig4 auth",
    "x-amz-security-token": "AgoGb3JpZ2luEKn////////xxxG1iKJBHjjvZH0DxcSqE889Wb3Mv+8PwMqrRe/O5dFFmP+9bQj+fSwVIUvmBplKkQB62x/xTelGHoCEOPXpBWLjT2OAUaBXOti7UZyfyMNgg56/Z58yxk4o2/37xPLbhXfODaL8kydFV8IaPJjdbJIX+a0kXycPLBnVIBdukUp9cMVD27mWN41u3w0VP5J8YiMPzrDnwKtb0U37naoIaknMBqNBDkMGQyHal/TBJ3wjJvJWVntrJvex0QKD8rDLHjaoiIYjBd+a04m2pKsBQJ9WQl02TTCPgRp0bb1oARF2hz0Xpi45Ba6a6E9SAL07UcRShTwX6rmxi0dZ38mkSbBMjI45Xg8r/VaRZx6/OyCq3u+nq4bgLCOMKqb/80F"
  },
  "data": "{\"data\":{\"func\":\"checkIfFacebookSignupComplete\",\"data\":{}}}",
  "method": "POST",
  "url": "https://xxx.execute-api.ap-northeast-1.amazonaws.com/dev/user/user"
}

Upvotes: 3

Related Questions