aws-sdk-js-v3 icon indicating copy to clipboard operation
aws-sdk-js-v3 copied to clipboard

type checking error with `fromEnv` in @aws-sdk/credential-providers

Open sudhirjena opened this issue 2 years ago • 29 comments

Describe the bug

While using @aws-sdk/credential-providers in a React typescript application having the following code:

import { initialize } from "@iot-app-kit/source-iotsitewise";
import { fromEnv } from "@aws-sdk/credential-providers";

const { query } = initialize({
  awsCredentials: fromEnv(),
  awsRegion: "us-east-1",
});

We encounter the following build error:

ERROR in ./src/App.tsx 16:18-25
export 'fromEnv' (imported as 'fromEnv') was not found in '@aws-sdk/credential-providers' (possible exports: fromCognitoIdentity, fromCognitoIdentityPool, fromTemporaryCredentials, fromWebToken)

Your environment

macOS

SDK version number

@aws-sdk/[email protected]

Is the issue in the browser/Node.js/ReactNative?

Browser

Details of the browser/Node.js/ReactNative version

Browsers:
    Chrome: 98.0.4758.109
    Firefox: 91.6.0
    Safari: 15.3

Steps to reproduce

Please share code or minimal repo, and steps to reproduce the behavior.

  • Create a new ReactJS application
npx create-react-app my-app --template typescript
  • Install minimal packages to reproduce issue
npm install @aws-sdk/credential-providers @iot-app-kit/source-iotsitewise
  • Add following code to App.tsx
import { initialize } from '@iot-app-kit/source-iotsitewise';
import { fromEnv } from '@aws-sdk/credential-providers';

const { query } = initialize({ awsCredentials: fromEnv(), awsRegion: 'us-east-1' });
  • Either run npm start or npm run build

Observed behavior

React app fails to run or build due to following type checking error

ERROR in ./src/App.tsx 16:18-25
export 'fromEnv' (imported as 'fromEnv') was not found in '@aws-sdk/credential-providers' (possible exports: fromCognitoIdentity, fromCognitoIdentityPool, fromTemporaryCredentials, fromWebToken)

Expected behavior

Although @aws-sdk/credential-providers has the following exported member, the type resolution fails. The type resolution for fromEnv should not fail.

export * from "./fromCognitoIdentity";
export * from "./fromCognitoIdentityPool";
export * from "./fromContainerMetadata";
export * from "./fromEnv";
export * from "./fromIni";
export * from "./fromInstanceMetadata";
export * from "./fromProcess";
export * from "./fromSSO";
export * from "./fromTemporaryCredentials";
export * from "./fromTokenFile";
export * from "./fromWebToken";

sudhirjena avatar Mar 03 '22 17:03 sudhirjena

i also face the same problem

sekamaneka avatar Mar 05 '22 15:03 sekamaneka

Receiving the same error but for fromIni as well

justenau avatar Mar 09 '22 18:03 justenau

Has anyone found a way to fix it? I have the same problem with fromIni

JuanUmbarila-engooden avatar Mar 11 '22 15:03 JuanUmbarila-engooden

One strange workaround that worked for me after a lot of experimenting was using version 3.40 of this package and importing fromIni with require statement instead of the usual import (even though my project is with es6) const { fromIni } = require("@aws-sdk/credential-providers");

Though that did not work with forEnv and this workaround doesn't solve the initial problem there is on the newest version :/

justenau avatar Mar 11 '22 15:03 justenau

One strange workaround that worked for me after a lot of experimenting was using version 3.40 of this package and importing fromIni with require statement instead of the usual import (even though my project is with es6) const { fromIni } = require("@aws-sdk/credential-providers");

Though that did not work with forEnv and this workaround doesn't solve the initial problem there is on the newest version :/

Thank you for you reply!!! I made that change in the code but when I call fromIni it still does not recognize it. fromIni is not a function

It's a strange behavior of the library

JuanUmbarila-engooden avatar Mar 11 '22 16:03 JuanUmbarila-engooden

Has anybody been able to resolve this?

I'm hitting the same issue with fromIni in v3.58.0.

import { fromIni } from "@aws-sdk/credential-providers";

The following error is raised:

export 'fromIni' (imported as 'fromIni') was not found in '@aws-sdk/credential-providers' (possible exports: fromCognitoIdentity, fromCognitoIdentityPool, fromTemporaryCredentials, fromWebToken)

Looking at index.web.ts, the exports match those returned in the above error message:

export * from "./fromCognitoIdentity";
export * from "./fromCognitoIdentityPool";
export * from "./fromTemporaryCredentials";
export * from "./fromWebToken";

Do additional exports need to be added here to match those within index.ts?

stuartmccoll avatar Apr 06 '22 12:04 stuartmccoll

Assigning to @ajredniwja for triaging.

trivikr avatar Apr 29 '22 23:04 trivikr

We don't export fromEnv in browser environments, as they don't have an environment to read variables from. Similar use case for fromIni which reads from configuration files, which do not exist in browser environments.

For a browser application, you need to use one of the following credential providers: fromCognitoIdentity, fromCognitoIdentityPool, fromTemporaryCredentials, fromWebToken

@sudhirjena @justenau Can you explain you use case where you plan to read credentials from environment or configuration files in the browser? If you're using server side rendering in your React application, does any configuration need to be set to use Node.js code from dependencies?

trivikr avatar Apr 29 '22 23:04 trivikr

It is incorrect to say that fromEnv wouldn't work in the browser environment, it is common for environment variables to be placed into process.env via build processes. The use case is for local development work flows - it is a huge burden to users of software to need to figure out how to set up something such as IAM to get a 'hello world' working.

Due to security concerns, it is highly recommended against guiding people towards hard coding strings directly into their code bases. Within Amazon, we are actually strictly forbidden from even suggesting this within our example repositories or code samples.

For this reason we need a good path forward on these local development use cases.

Additionally, for any credential-providers which are intentionally not supported in the browser, they should be:

  • documented (of which these omissions are not)
  • throw an error, with an intelligible message, rather than simply being omitted from the bundles which causes lots of confusion.

diehbria avatar May 02 '22 17:05 diehbria

it is common for environment variables to be placed into process.env via build processes

Can you share an example or documentation of how it's done in case of create react app? I'm wondering if it's specific to React or CRA or used extensively in frontend ecosystem.

  • documented (of which these omissions are not)

I created a feature request to add documentation at https://github.com/aws/aws-sdk-js-v3/issues/3586

  • throw an error, with an intelligible message, rather than simply being omitted from the bundles which causes lots of confusion.

The existing error clearly mentions fromEnv is not exported for browser environment. The users shouldn't try to import credential provider not available in their environment.

trivikr avatar May 03 '22 00:05 trivikr

The existing error clearly mentions fromEnv is not exported for browser environment. The users shouldn't try to import credential provider not available in their environment.

Which is not documented, and clearly many people think this is an accidental bug, as evident by this ticket. This method of communicating the API is not a good design, because the library still exports them as typescript types.

Environment variables in the front end:

  • https://create-react-app.dev/docs/adding-custom-environment-variables/
  • https://www.npmjs.com/package/rollup-plugin-inject-process-env
  • https://webpack.js.org/plugins/environment-plugin/ this is not a CRA specific thing, every modern front-end build system has ability to inject process.env. It's used commonly for local development configurations.

diehbria avatar May 03 '22 17:05 diehbria

  • create-react-app.dev/docs/adding-custom-environment-variables

This wiki clearly mentions

WARNING: Do not store any secrets (such as private API keys) in your React app!

It's not explicitly called out in homepage of rollup and webpack plugins, the SDK shouldn't expose fromEnv for frontend which would encourage users to do something which is not a standard. Although injecting process.env is supported by CRA directly, and in rollup and webpack through plugins - it's not a browser standard to have environment variables in the frontend.

If we officially expose fromEnv in the frontend, users may prefer it over frontend specific standard credential providers fromCognitoIdentity, fromCognitoIdentityPool, fromTemporaryCredentials and fromWebToken.

Here's the workaround to explicitly set credentials if you're injecting them through process.env

const client = new ClientName({
  credentials: {
    accessKeyId: process.env.AWS_ACCESS_KEY_ID,
    secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY,
  },
})

This explicit code during client creation will ensure that it's not recommended by the SDK. I'm marking this issue as guidance.

trivikr avatar May 06 '22 21:05 trivikr

It's used commonly for local development configurations.

Out of curiosity to check if any follow-up is required from SDK: How do frontend developers ensure that environment variables are removed when pushing to production?

trivikr avatar May 06 '22 21:05 trivikr

Another question: Would it be helpful is SDK provides a different utility to improve local development experience for frontend? If yes, what that utility should look like?

We can create a new feature request for this utility. I'm assuming this utility (say @aws-sdk/util-frontend) will work only in local environment (like when NODE_ENV=dev in case of environment variables).

trivikr avatar May 06 '22 21:05 trivikr

If the decision is made not to include these, I think it should be considered to have the credential providers throw errors at run time which point towards the documentation and explain these aren't supported.

The message "export 'fromEnv' (imported as 'fromEnv') was not found in '@aws-sdk/credential-providers" leads the user to think it's an issue with the SDK, as we can see by the comments made in the issue. The typescript definitions also indicate it should exist, making for a confusing experience.

My use case for fromEnv is to write documentation for users of my teams library for simple setup - fromEnv for us would allow us to give people a way to simply set up without copying and pasting credentials into their library, without us writing confusing documentation around implementing their own credential provider or instantiating multiple SDKs with process env variables

diehbria avatar May 12 '22 16:05 diehbria

I have just encountered this same issue. I don't really understand the logic of not including fromEnv / fromProcess / fromIni in the exports for the browser version.

How do frontend developers ensure that environment variables are removed when pushing to production?

Using AWS, we can inject secrets into the environment of containerized applications at runtime. This is even the recommended practice with ECS according to the documentation. We can also make the environmental variables accessible from containers by mapping the environmental variables of an EC2 from EB to the container using docker-compose according to the EB developer's guide. It's not a stretch to use an entrypoint script in a container to retrieve the secrets from the environment (as described in the documentation) and place them in a credentials file which the React application can access.

I would also like to emphasize @diehbria 's comment:

If the decision is made not to include these, I think it should be considered to have the credential providers throw errors at run time which point towards the documentation and explain these aren't supported.

My question then becomes, what is the recommendation from AWS if we're not able to import fromEnv / fromProcess / fromIni in a containerized React application?

evanottinger avatar Jul 15 '22 20:07 evanottinger

I believe I am having a related issue, though through the lens of NextJS. In a getServerSideProps call which executes in a nodejs runtime:

import { DynamoDBClient } from '@aws-sdk/client-dynamodb';
import { DynamoDBDocumentClient } from '@aws-sdk/lib-dynamodb';
import { fromIni } from '@aws-sdk/credential-providers';

const ddbClient = new DynamoDBClient({
    credentials: fromIni({
        profile: 'saml',
    }),
    region,
});

allows me to successfully use a GetCommand to retrieve data, on the server, but then my locally running environment throws TypeError: (0 , _aws_sdk_credential_providers__WEBPACK_IMPORTED_MODULE_2__.fromIni) is not a function in the client.

I then tried to use the node credential provider:

import { DynamoDBClient } from '@aws-sdk/client-dynamodb';
import { DynamoDBDocumentClient } from '@aws-sdk/lib-dynamodb';
import { defaultProvider } from '@aws-sdk/credential-provider-node';

const provider = defaultProvider({
     profile: 'saml',
});

const ddbClient = new DynamoDBClient({
    credentialDefaultProvider: provider,
    region,
});

and encounter an error:

./node_modules/@aws-sdk/credential-provider-node/node_modules/@aws-sdk/credential-provider-process/dist-es/resolveProcessCredentials.js:2:0
Module not found: Can't resolve 'child_process'

I could not find anything explaining when to use which module, why they are different (when they seem to do the same thing), or these errors.

It sounds like typeError is because fromIni is being excluded from the webpack bundle (which is not document and not obvious as others have said). So i should be using the node version, but following the example, everything fails and there is no other documentation to help resolve it.

alamberti avatar Apr 05 '23 17:04 alamberti

Any update on this? I too am needing to use saml2aws creds with fromIni in a Vue app. I'm getting the "Syntax Error: ambiguous indirect export: fromIni" error message. I've followed the code instructions from the latest AWS SDK version 3 documentation for credential-providers.

ecarrell avatar Aug 17 '23 21:08 ecarrell

I have the same issue in local development, I got

No matching export in "node_modules/@aws-sdk/credential-providers/dist-es/index.browser.js" for import "fromIni"

Now I'm stuck on this.

yongzhang avatar Nov 15 '23 09:11 yongzhang

Any update on this?

jayPatel222 avatar Dec 29 '23 05:12 jayPatel222

I am also facing the same issue, appreciate any updates on the matter.

theSJace avatar Jan 09 '24 11:01 theSJace

same, getting a fromIni is not a function

jinglongwu avatar Jan 14 '24 18:01 jinglongwu

Any workarounds for this?

marc-at avatar Jan 26 '24 21:01 marc-at

any update for this?

jfoxx-aperia avatar Feb 19 '24 21:02 jfoxx-aperia

fromEnv will not be provided in the browser, since process is a Node.js global and to use it would mean leaving credentials readable in an easily discoverable global object, vulnerable to 3rd party scripts.

Webpack may transform the Node.js process env to the application, but this is only a simulated effect and additionally not consistent across bundlers.

Any credential supplying async function can be provided to an SDK client. It will be called automatically when credentials are needed and when they expire (if expiration is set).

import { S3Client } from "@aws-sdk/client-s3";

const provider = async () => {
  return {
    accessKeyId: "...", 
    secretAccessKey: "...",
    sessionToken: "...",
    expiration: new Date( /*...*/ )
  }
};

new S3Client({
  credentials: provider
});

If you really want to use process.env, write the provider function in such a way that it reads from your simulated process.env. This is identical to the SDK's Node.js fromEnv function, but the key difference is we do not recommend it, and therefore don't provide it.

As documented here: https://www.npmjs.com/package/@aws-sdk/credential-providers The following providers are not available in the browser: fromContainerMetadata, fromInstanceMetadata, fromEnv, fromIni, fromNodeProviderChain, fromProcess, fromSSO, fromTokenFile

kuhe avatar Mar 01 '24 18:03 kuhe

@kuhe Not sure if this comment was directed at everyone or some other poster... In our situation, we are not trying to use AWS from the browser at all (we don't provide any credentials there). We are trying to pass container credentials to our TRPC server and we are getting these warnings. They are new and large warnings that didn't use to be there. The warnings really don't apply to us at all. We would like to be rid of them. Is there some way to restrict this warning just to cases where someone is trying to use these in the browser?

jove4015 avatar Mar 15 '24 16:03 jove4015

@jove4015 please create a new issue with instructions on how to replicate the error.

kuhe avatar Mar 18 '24 13:03 kuhe

Hey there,

the last two days I was working on a vue application and faced the same problem, whereby the mentioned solution of kuhe worked. After having it working I took myself some time to re-think things and the point is that Vue, React, ect. are frontend frameworks which are made to create an application for the browser, meaning they show all their information in the code. Now out of security perspective it makes sense that these functions aren't available for frontend applications which are running in the browser, because there is the risk to show the credentials in the code.

In my case I'll have a lambda in between the application to handle the s3 authentication as well as the up- and download of objects, which then will be passed to the FE-App. Another way how to handle it, would be to make the S3 bucket public and work with resource permissions and CORS rules to make sure that the traffic is safe.

mikekinlock avatar Apr 05 '24 06:04 mikekinlock

I have a similar issue with using fromNodeProviderChain in a nextjs project.

We use process.envs to determine whether to fetch a public lambda for development or a private lambda (which is what is on our production sites) which is what is utilizing this.

Locally this causes an issue when we build nextjs packages unless I change it to CJS syntax for the import.

Most noticably, this error is incorrect; as its not so much that its a bad import reference, just that it isn't designed to be used in this way (even though, it works in the way that it is being used by everyone in this thread).

rforster-dev avatar Apr 17 '24 15:04 rforster-dev