Background: I am investigating possible tech stacks for a project, so I am trying a bunch of things I'm not very familiar with. ( rough going, obviously )
I see Amazon recommends Amplify for React Native apps that need to interact with AWS services, but I need to definitively verify if the SDK is an option or not, by either producing a working example as proof, or understanding why a working example isn't possible.
My use case is logging in with a Cognito user. I have little code sample that works fine in Node, but in a React Native App it just gives me:
[TypeError: Cannot read property 'apply' of undefined]
when running in React Native. Maybe I'm just missing something obvious, React Native or JavaScript related.
Here is the code sample that runs in Node:
import {
AuthFlowType,
CognitoIdentityProviderClient,
InitiateAuthCommand,
} from '@aws-sdk/client-cognito-identity-provider';
const region = 'us-east-1';
const cognitoClient = new CognitoIdentityProviderClient({
region,
});
initializeAuthorizationLogin('user', 'aGoodPassword');
async function initializeAuthorizationLogin(
username,
password,
) {
const params = {
ClientId: 'theclientid',
AuthFlow: AuthFlowType.USER_PASSWORD_AUTH,
AuthParameters: {
USERNAME: username,
PASSWORD: password,
},
};
const initiateAuthCommand = new InitiateAuthCommand(params);
try {
const response = await cognitoClient.send(initiateAuthCommand);
console.log(response);
} catch (e) {
console.log(e);
}
}
In React Native, App.tsx looks like this:
import {
AuthFlowType,
CognitoIdentityProviderClient,
InitiateAuthCommandInput,
InitiateAuthCommand,
} from '@aws-sdk/client-cognito-identity-provider';
import React from 'react';
import {
Button,
SafeAreaView,
ScrollView,
StatusBar,
Text,
View,
} from 'react-native';
async function initializeAuthorizationLogin(
username: string,
password: string,
) {
const params: InitiateAuthCommandInput = {
ClientId: 'theclientid',
AuthFlow: AuthFlowType.USER_PASSWORD_AUTH,
AuthParameters: {
USERNAME: username,
PASSWORD: password,
},
};
const initiateAuthCommand = new InitiateAuthCommand(params);
try {
const region = 'us-east-1';
const cognitoClient = new CognitoIdentityProviderClient({
region,
});
const response = await cognitoClient.send(initiateAuthCommand);
console.log(response);
} catch (e) {
console.log(e);
}
}
function tryLogin() {
initializeAuthorizationLogin('user', 'aGoodPassword');
}
function App(): React.JSX.Element {
return (
<SafeAreaView>
<StatusBar />
<ScrollView contentInsetAdjustmentBehavior="automatic">
<View>
<Text>A blank starting page</Text>
<Button onPress={tryLogin} title="Try logging in" />
</View>
</ScrollView>
</SafeAreaView>
);
}
export default App;
The Node example provides a 200 and the expected IdToken, AccessToken, RefreshToken. The React Native App provides the TypeError. I don't know why.
I'm going to self-answer this one in case it helps someone else out in future.
TLDR:
Add
import '@aws-sdk/util-endpoints'
;
and install the appropriate package from NPM. Apparently Metro and the AWS SDK cooks up some horrible concoction ( which would explain why it works great in Node and not at all in React Native )
It was an adventure in experimentation, but I stumbled upon this: https://github.com/aws/aws-sdk-js-v3/issues/5777 and presto, it worked.
( I ran into another issue like this right after, that was also solved by the same 'technique'. struggling to fix: "ReferenceError: Property 'ReadableStream' doesn't exist" helped resolve that. )
I think there's a different root cause here that can perhaps be resolved by updating the Metro config. Doing this kind of thing for a production app seems squishy.