Closed suhailsaqan closed 3 years ago
Any progress on this? If you need more information to reproduce this let me know.
Good afternoon :wave: would you mind trying to console log users
and also wrap the query in a try/catch and console log the error you're getting if possible?
Hi 👋🏻. It does not return any user but throws an error. The error is undefined
.
I haven't been able to reproduce this issue in a React Native with the same amplify packages and versions. Have you been able to successfully create users before trying to query for them?
This is my code
package.json
{
"main": "node_modules/expo/AppEntry.js",
"scripts": {
"start": "expo start",
"android": "expo start --android",
"ios": "expo start --ios",
"web": "expo start --web",
"eject": "expo eject"
},
"dependencies": {
"@aws-amplify/api": "3.2.30",
"@react-native-community/netinfo": "6.0.0",
"amazon-cognito-identity-js": "4.6.0",
"aws-amplify": "3.3.27",
"aws-amplify-react-native": "4.3.2",
"expo": "~41.0.1",
"expo-status-bar": "~1.0.4",
"react": "16.13.1",
"react-dom": "16.13.1",
"react-native": "https://github.com/expo/react-native/archive/sdk-41.0.0.tar.gz",
"react-native-web": "~0.13.12"
},
"devDependencies": {
"@babel/core": "^7.9.0"
},
"private": true
}
schema.graphql
type User @model {
id: ID!
email: AWSEmail!
phone: AWSPhone!
first_name: String!
last_name: String!
profile_picture: AWSURL
}
App.js
import { StatusBar } from "expo-status-bar";
import React, { useEffect } from "react";
import { StyleSheet, Text, View } from "react-native";
import awsconfig from "./src/aws-exports";
import Amplify, { API, graphqlOperation } from "aws-amplify";
import { listUsers } from "./src/graphql/queries";
Amplify.configure(awsconfig);
export default function App() {
const init = async () => {
try {
const email = "test@gmail.com";
const users = await API.graphql(
graphqlOperation(listUsers, {
filter: { email: { eq: email } },
})
);
console.log(users);
} catch (error) {
console.log(error);
}
};
useEffect(() => {
init();
}, []);
return (
<View style={styles.container}>
<Text>Open up App.js to start working on your app!</Text>
<StatusBar style="auto" />
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: "#fff",
alignItems: "center",
justifyContent: "center",
},
});
console log
No it's the same thing when i try to create them. I created a user from the console though and that works normally.
It also tells me that there is no user after logging in with Cognito. Is that normal?
I don't think that's normal 😅 how are you logging in or using Auth in your project? If you're using Cognito user pools as the auth for your graphQL api, I don't think you'd be able to make any requests if you're not properly logged in.
Would you mind sharing more of the code? I'm thinking there's probably an issue with the way auth is set up in the project.
This is the basics of my code. I am first using Cognito to sign in then querying the users data from the api.
try {
const user = await Auth.signIn(email, password);
console.log('successfully signed in: ' + user.getUsername());
const users = await API.graphql(
graphqlOperation(listUsers, {
filter: {email: {eq: email}},
}),
);
} catch ({message}) {
console.log('sign in failed', message);
Are you importing Auth from aws-amplify or from the amazon-cognito-identity-js package? If you are, we recommend importing Auth from Amplify and letting it take care of Auth. It uses the same cognito library under the hood but it will keep the logged in user in the same instance it will use to make the graphql calls.
Like this?:
import {Auth, API, graphqlOperation} from 'aws-amplify';
Quick question: In your error log, you're getting "signIn MFA required", so the Auth.signIn
probably isn't really signing you in. I think if you were to console log the user
returned from it you'll see that there's a challengeName. It might be that your user doesn't have MFA setup yet. For that I recommend following this part of the documentation:
https://docs.amplify.aws/lib/auth/mfa/q/platform/js#setup-totp
Does SMS verification not count as MFA? Because when a user signs up it sends an SMS message and I use this to confirm the user:
await Auth.confirmSignUp(username,confirmationCode);
What’s the difference?
That SMS/Email verification code is to verify the user's account/email. The MFA code is to add an extra layer of security to authenticating (logging in) the user. So, when they try to log in they need to also provide a security code (TOTP: Time-Based One Time Password) from an app like Google Authenticator.
There is Auth.confirmSignUp
but then there is Auth.confirmSignIn
which accepts the CognitoUser object from Auth.signIn
, the MFA code from either SMS or TOTP depending on what you chose during the auth configuration, and a respective mfaType
of either "SMS_MFA"
or "SOFTWARE_TOKEN_MFA"
With your auth configuration, the user will not be fully authenticated in until Auth.confirmSignIn
is successfully resolved.
This is how I'm handling it in my reproduction code
After attempting to sign in, set up TOTP for the user with their CognitoUser from Auth.signIn
, display the token to them (I set it to state to display for them)
async function getTotpToken() {
try {
const token = await Auth.setupTOTP(user);
setTotpToken(token);
} catch (error) {
console.log(error);
}
}
The user should then take the token we gave them and use it in an app that generates one time passwords (I used the Google Authenticator browser extension for my reproduction)
You'll need to allow the user to input the generated one time password so you can verify it
async function verifyTotpToken() {
const {token} = formState;
try {
const res = await Auth.verifyTotpToken(user, token);
} catch (error) {
console.log(error);
}
}
From then on, the user will need to be logged in like so after Auth.signIn
, which will give you the CognitoUser and a challengeName
meaning another step is required before fully authenticating.
async function confirmSignIn() {
const {code} = formState;
try {
const confirmedSignIn = await Auth.confirmSignIn(
user,
code,
'SOFTWARE_TOKEN_MFA',
);
console.log({confirmedSignIn});
onConfirmSignIn();
} catch (error) {
console.log(error);
}
}
Otherwise, you'd keep getting this even after Auth.signIn
might've seemed like it worked because it didn't error out and returned some user info
Here's what it looks like when I call Auth.signIn
, try to use Auth.currentAuthenticatedUser
, and finally Auth.confirmSignIn
. You'll see that I get The user is not authenticated
until I call Auth.confirmSignIn
, then it works.
I used software token for my reproduction so you'd just have to make sure you pass "SMS_MFA"
to Auth.confirmSignIn
if you used "SMS" in your auth config instead.
Thank you! I'll try that now but I was trying to save the users information through the API to the database right after they sign up. How can I do it like that because it does not let the user use the api until doing the confirmSignin
?
Do I just run the confirmSignup
then confirmSignin
then the API queries on signup?
I would suggest using a Cognito Post Confirmation trigger to create the user in your API. https://medium.com/hackernoon/how-to-add-new-cognito-users-to-dynamodb-using-lambda-e3f55541297c
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.
Before opening, please confirm:
JavaScript Framework
React Native
Amplify APIs
GraphQL API
Amplify Categories
auth, api
Environment information
Describe the bug
I have reported this issue before but then the code worked so it got closed. However, now it is happening again:
I am trying to query the API with the following code, however, it is erroring with an 'undefined' error.
The network is empty when I query the API:
This is the code:
Expected behavior
I expect it to return a graphql result.
Reproduction steps
Code Snippet
Log output