Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

API signing doesn't work with proxy #3168

Closed
chmelevskij opened this issue Apr 26, 2019 · 6 comments
Closed

API signing doesn't work with proxy #3168

chmelevskij opened this issue Apr 26, 2019 · 6 comments
Labels
API Related to REST API issues duplicate If marked with duplicate, issue will be closed & original will be added for traceability feature-request Request a new feature

Comments

@chmelevskij
Copy link

chmelevskij commented Apr 26, 2019

Describe the bug
API request signing fails when requests are going through a proxy.

To Reproduce

  1. Create an REST api protected with IAM.
  2. Setup api
API.configure({
  endpoints: [
    {
      name: 'myApi',
      endpoint: `${window.location.protocol}//${window.location.host}`
    }
  ],
});
3. Setup a `webpack.devServer` proxy
```javascript
  proxy: {
    '/api': {
      target: "<api-gw-url>",
      changeOrigin: true,
      pathRewrite: { '^/api': '' },
    },
  }
  1. In the app use API.get or any other method.

Expected behavior
I expect the request to work fine as with the custom domain setup.

Logs

[DEBUG] 39:43.340 RestClient - GET http://localhost:8000/mordor/networks/
ConsoleLogger.js:78 [DEBUG] 39:43.344 Credentials - getting credentials
ConsoleLogger.js:78 [DEBUG] 39:43.345 Credentials - picking up credentials
ConsoleLogger.js:78 [DEBUG] 39:43.345 Credentials - getting new cred promise
ConsoleLogger.js:78 [DEBUG] 39:43.346 Credentials - checking if credentials exists and not expired
ConsoleLogger.js:88 [DEBUG] 39:43.346 Credentials - is this credentials expired? CognitoIdentityCredentials {expired: false, expireTime: Fri Apr 26 2019 18:39:21 GMT+0200 (Central European Summer Time), accessKeyId: "xxxxx", sessionToken: "xxxxxxxxxxxx", params: {…}, …}accessKeyId: "xxxxxxxxx"authenticated: truecognito: features.constructor {config: Config, isGlobalEndpoint: false, endpoint: Endpoint, _events: {…}, MONITOR_EVENTS_BUBBLE: ƒ, …}data: {IdentityId: "eu-west-1:xxxxx", Credentials: {…}}expireTime: Fri Apr 26 2019 18:39:21 GMT+0200 (Central European Summer Time) {}expired: falseparams: {IdentityPoolId: "eu-west-1:xxxxx", Logins: {…}, IdentityId: "eu-west-1:xxxxx", RoleSessionName: "web-identity"}sessionToken: "xxxxxx"sts: features.constructor {config: Config, isGlobalEndpoint: true, endpoint: Endpoint, _events: {…}, MONITOR_EVENTS_BUBBLE: ƒ, …}webIdentityCredentials: WebIdentityCredentials {expired: true, expireTime: null, accessKeyId: undefined, sessionToken: undefined, params: {…}, …}_clientConfig: {region: "eu-west-1"}_identityId: "eu-west-1:xxx"identityId: (...)secretAccessKey: "xxxxxx"get identityId: ƒ ()set identityId: ƒ (identityId)__proto__: Credentials
ConsoleLogger.js:78 [DEBUG] 39:43.347 Credentials - credentials not changed and not expired, directly return
ConsoleLogger.js:78 [DEBUG] 39:43.350 Signer - GET
/mordor/networks/

host:localhost:8000
x-amz-date:20190426T153943Z
x-amz-security-token:xxxxx

host;x-amz-date;x-amz-security-token
e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
ConsoleLogger.js:81 [DEBUG] 39:43.354 Signer {region: "eu-west-1", service: "execute-api"}region: "eu-west-1"service: "execute-api"__proto__: Object
ConsoleLogger.js:88 [DEBUG] 39:43.356 RestClient - Signed Request:  {method: "GET", url: "http://localhost:8000/mordor/networks/", host: "localhost:8000", path: "/mordor/networks/", headers: {…}, …}data: nullheaders: Authorization: "AWS4-HMAC-SHA256 Credential=xxx/20190426/eu-west-1/execute-api/aws4_request, SignedHeaders=host;x-amz-date;x-amz-security-token, Signature=xxxx"X-Amz-Security-Token: "xxxx"x-amz-date: "20190426T153943Z"__proto__: Objecthost: "localhost:8000"method: "GET"path: "/mordor/networks/"url: "http://localhost:8000/mordor/networks/"__proto__: Object
Promise {<pending>}
xhr.js:178 GET http://localhost:8000/mordor/networks/ 403 (Forbidden)
dispatchXhrRequest @ xhr.js:178
xhrAdapter @ xhr.js:12
dispatchRequest @ dispatchRequest.js:59
Promise.then (async)
request @ Axios.js:51
wrap @ bind.js:9
umi../node_modules/@aws-amplify/api/lib/RestClient.js.RestClient._signed @ RestClient.js:288
(anonymous) @ RestClient.js:168
Promise.then (async)
(anonymous) @ RestClient.js:168
step @ RestClient.js:52
(anonymous) @ RestClient.js:33
(anonymous) @ RestClient.js:27
umi../node_modules/@aws-amplify/api/lib/RestClient.js.__awaiter @ RestClient.js:23
umi../node_modules/@aws-amplify/api/lib/RestClient.js.RestClient.ajax @ RestClient.js:111
umi../node_modules/@aws-amplify/api/lib/RestClient.js.RestClient.get @ RestClient.js:183
(anonymous) @ API.js:179
step @ API.js:40
(anonymous) @ API.js:21
(anonymous) @ API.js:15
umi../node_modules/@aws-amplify/api/lib/API.js.__awaiter @ API.js:11
umi../node_modules/@aws-amplify/api/lib/API.js.APIClass.get @ API.js:158
(anonymous) @ VM61:1
ConsoleLogger.js:81 [DEBUG] 39:43.771 RestClient Error: Request failed with status code 403
    at createError (createError.js:16)
    at settle (settle.js:18)
    at XMLHttpRequest.handleLoad (xhr.js:77)
index.js:1 Error: Request failed with status code 403
    at createError (createError.js:16)
    at settle (settle.js:18)
    at XMLHttpRequest.handleLoad (xhr.js:77)
console.<computed> @ index.js:1
Promise.then (async)
(anonymous) @ VM61:1

Error response

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
'GET
/dev/networks/

host:yvnuzltm22.execute-api.eu-west-1.amazonaws.com
x-amz-date:20190426T153943Z
x-amz-security-token:xxxx

host;x-amz-date;x-amz-security-token
e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855'

The String-to-Sign should have been
'AWS4-HMAC-SHA256
20190426T153943Z
20190426/eu-west-1/execute-api/aws4_request
136e286beeabed0d66714e6cdfe1fb9278e2bf93f5b39281e4e7ade99145c5e8'
@chmelevskij chmelevskij changed the title Allow Proxied API usage API signing doesn't work proxy Apr 26, 2019
@chmelevskij chmelevskij changed the title API signing doesn't work proxy API signing doesn't with work proxy Apr 26, 2019
@jordanranz jordanranz added the API Related to REST API issues label Apr 26, 2019
@chmelevskij chmelevskij changed the title API signing doesn't with work proxy API signing doesn't work with proxy Apr 29, 2019
@manueliglesias
Copy link
Contributor

Hi @chmelevskij

Does it still fails if you do changeOrigin: false, ?

The API request is signed using sigv4 and the host header info is used to sign the request, so any alterations will make the signature validation fail.

@manueliglesias manueliglesias added the question General question label Apr 30, 2019
@chmelevskij
Copy link
Author

chmelevskij commented Apr 30, 2019

It fails in both cases. It also failing in using Netlify redirects.

In the case of the local setup there is a mismatch in protocols/ports somewhere so it ends up with this error.

[HPM] Error occurred while trying to proxy request /xxx/ from localhost:8000 to https://zzzzzz.execute-api.eu-west-1.amazonaws.com/dev (EPROTO) (https://nodejs.org/api/errors.html#errors_common_system_errors)

@manueliglesias
Copy link
Contributor

@chmelevskij Yeah, the mismatch is introduced by the webpack dev server.

Do you need to proxy those calls?

From https://facebook.github.io/create-react-app/docs/proxying-api-requests-in-development:

Keep in mind that proxy only has effect in development (with npm start), and it is up to you to ensure that URLs like /api/todos point to the right thing in production. You don’t have to use the /api prefix. Any unrecognized request without a text/html accept header will be redirected to the specified proxy.

The proxy option supports HTTP, HTTPS and WebSocket connections.
If the proxy option is not flexible enough for you, alternatively you can:

  • Configure the proxy yourself
  • Enable CORS on your server (here’s how to do it for Express).
  • Use environment variables to inject the right server host and port into your app.

The recommendation here would be to not proxy calls to your API GW.

@chmelevskij
Copy link
Author

That is what I ended up doing as a workaround. Enabling CORS on API gw and using that.

It would be a nice feature to have, because then it's possible avoid dealing with CORS setup. In cases where api gateway is not managed by amplify setting up CORS properly is just extra work.

I just have a suspicion that if it's not working with proxy, it might be a pain to deal with custom domains as well.

@stale
Copy link

stale bot commented Jun 15, 2019

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

@sammartinez sammartinez removed the question General question label Nov 19, 2019
@cwomack cwomack added the duplicate If marked with duplicate, issue will be closed & original will be added for traceability label Apr 30, 2024
@cwomack
Copy link
Member

cwomack commented Apr 30, 2024

In an effort to consolidate the context, comments, and criteria for success regarding improved support for proxies with Amplify, we'll be closing this issue in favor of the more recent #13048. Please follow that issue and leave any additional feedback there going forward. Thank you!

@cwomack cwomack closed this as not planned Won't fix, can't repro, duplicate, stale Apr 30, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
API Related to REST API issues duplicate If marked with duplicate, issue will be closed & original will be added for traceability feature-request Request a new feature
Projects
None yet
Development

No branches or pull requests

5 participants