aws-amplify / amplify-js

A declarative JavaScript library for application development using cloud services.
https://docs.amplify.aws/lib/q/platform/js
Apache License 2.0
9.44k stars 2.13k forks source link

Credentials Not Being Passed Properly on Electron App #3321

Closed themuli closed 5 years ago

themuli commented 5 years ago

Describe the bug

I am using Amplify for authentication and communicating with my AWS Lambda backend. For some reason, the CognitoIdentity and CognitoPoolIdentity are not being passed by Amplify.

To Reproduce Steps to reproduce the behavior:

  1. Clone project electron-react-boilerplate
  2. Configure Amplify
  3. Call Auth.signIn(username, password)
  4. Call Lambda endpoint and receive 500 error because CognitoIdentity is null.

Expected behavior Calling API should work after signing in. I am following this tutorial: Amplify Javascript Authentication

Screenshots I have window.LOG_LEVEL = 'DEBUG'; turned on and here are some screenshots:

Part 1 Part 2 Part 3 Part 4

Desktop (please complete the following information):

Additional context Add any other context about the problem here.

Sample code

Amplify.configure({
  Auth: {
    mandatorySignIn: true,
    region: 'us-east-2',
    userPoolId: '***',
    identityPoolId: '***',
    userPoolWebClientId: '***'
  },
  Storage: {
    region: 'us-east-2',
    bucket: '***',
    identityPoolId: '***'
  },
  API: {
    endpoints: [
      {
        name: 'items',
        endpoint: '***',
        region: 'us-east-2'
      }
    ]
  }
});

Signing in and calling API process:

await Auth.signIn('user@email.com', 'password');
      console.log('calling API');
      const params = {
        deviceId: 'sfdasdfsdafsadfsdfafsfd',
        osType: 'someOSType',
        osVersion: 'someOSVersion'
      };
      const registrationResult = await API.put('items', '/devices', {
        body: params
      });
themuli commented 5 years ago

@powerful23 Can you help me get unblocked? I believe you resolved a similar issue 2 weeks ago: https://github.com/aws-amplify/amplify-js/issues/1178 and https://github.com/aws-amplify/amplify-js/issues/1178#issuecomment-494913075

themuli commented 5 years ago

@haverchuck Would it be possible for someone to look at this please? TIA.

haverchuck commented 5 years ago

Hi @themuli -

Are you at any point using AWS.config.credentials in your code? Thanks.

themuli commented 5 years ago

@haverchuck No I am not. I also tried the solution here and it didn't work for us: API headers not signed when AWS_PROFILE env var is set #3132

themuli commented 5 years ago

I've discovered the root cause.

The aws-sdk library (used by aws-amplify to make the calls) mistakes the renderer process in Electron for a nodejs environment. In the nodejs case, It is also very ambitious when it comes to fetching AWS credentials from the user's home directory and https://github.com/aws/aws-sdk-js/issues/1276.

I've figured out a workaround that tells the aws-sdk that we're in a browser environment and opened a pull request: https://github.com/aws-amplify/amplify-js/pull/3357

The fix is to set process.browser = true; in the Electron app's root index.html or app.html.

Ideally, the AWS SDK team would fix this and coordinate with the Amplify team on an update. In the meantime, this solution should prevent future Electron developers from going through the same pains as I did.

themuli commented 5 years ago

@manueliglesias @haverchuck Can you have someone look at my pull request? It's a really short documentation change.

themuli commented 5 years ago

To further clarify:

Logging in works fine because Amplify is passing in an email/username and password to authenticate a Cognito identity. However, when using Amplify to call an AWS API, the aws-sdk prioritizes uses the user's root sdk credentials instead of the Cognito credentials that Amplify just saved. This mismatch is why I was receiving a 500 (CognitoIdentity is null) instead of 400 (unauthorized) error.

manueliglesias commented 5 years ago

Hi @themuli

Thanks for the investigation and detailed explanation!

I looked into this a little and I think you can do

AWS.CredentialProviderChain.defaultProviders = [];

For reference, I see where the problem starts, from https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/CredentialProviderChain.html#defaultProviders-property

The default set of providers used by a vanilla CredentialProviderChain.

In the browser:

AWS.CredentialProviderChain.defaultProviders = []

In Node.js:

AWS.CredentialProviderChain.defaultProviders = [
  function () { return new AWS.EnvironmentCredentials('AWS'); },
  function () { return new AWS.EnvironmentCredentials('AMAZON'); },
  function () { return new AWS.SharedIniFileCredentials(); },
  function () { return new AWS.ECSCredentials(); },
  function () { return new AWS.ProcessCredentials(); },
  function () { return new AWS.EC2MetadataCredentials() }
]

Default Value:

AWS.CredentialProviderChain.defaultProviders = []

I am closing this issue and the PR, but please let us know if this didn't work so we can re-open appropriately

paragbaxi commented 4 years ago

@manueliglesias looked into this. in order to access the AWS namespace, I'd have to configure it with an access key in the electron package. if I'm distributing this electron app, then those keys would be shared. Is there another solution?

@themuli thank you! I added the following to _app.tsx under <Head> <script dangerouslySetInnerHTML={{ __html:process.browser=true;}} />

This worked!

github-actions[bot] commented 3 years ago

This issue has been automatically locked since there hasn't been any recent activity after it was closed. Please open a new issue for related bugs.

Looking for a help forum? We recommend joining the Amplify Community Discord server *-help channels or Discussions for those types of questions.