Describe the bug
The app crashes when using a custom auth with Cognito.
To Reproduce
I am trying to implement a client for using the passwordless sms login.
The backend is already done here:
https://serverlessrepo.aws.amazon.com/applications/arn:aws:serverlessrepo:us-east-1:552623489034:applications~amplify-passwordless-sms-auth
https://github.com/mobilequickie/amplify-passwordless-sms-auth
Regarding my client, I created the awsconfiguration.json file using "authenticationFlowType": "CUSTOM_AUTH"
First step: I call, AWSMobileClient.default().signUp (username is a phone number and password is a dummy uuid), it seems everything works fine and a new user is created in Cognito.
Second step: When that is done, I call AWSMobileClient.default().signIn, which in theory will trigger the lambda functions and send the SMS message, but that method crashes.
The app is crashing in this line of code:
serviceSecretBlock:[[NSData alloc] initWithBase64EncodedString:authDetails.challengeParameters[@"SECRET_BLOCK"] options:0]];
line 914, file AWSCognitoIdentityUser.m
The reason is because the challengeParameters dictionary only has one key called "USER_NAME", and nothing about "SECRET_BLOCK".
This is the log when the app crashes:
2019-12-09 13:44:47.250699+0000 XXXXXX[35184:6274992] * Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '* -[_NSPlaceholderData initWithBase64EncodedString:options:]: nil string argument'
Can you check that? Do you know where the problem is?
Without that, I cannot implement passwordless sms login in my app.
If you need a sample project, let me know and I do it.
Thanks a lot.
Which AWS service(s) are affected?
AWS Cognito
Expected behavior
No crash.
Environment(please complete the following information):
Device Information (please complete the following information):
Additional context
Add any other context about the problem here.
@Ricardo1980 if you are using the latest AWSMobileClient for CUSTOM_AUTH flow, I had the same crashing issue and fixed it TEMPORARILY by modifying the DefineAuthChallenge Lambda function with the following code below. Please let me know if this works and we'll try to get the SRP_A and dummy password issue explained and resolved by the SDK team, hopefully.
Just go to your DefineAuthChallenge function, comment out the old code and replace with this and then attempt to authenticate from your iOS app. If this doesn't work, I have a sample iOS app that I can share that is working well. Good luck!
'use strict';
exports.handler = async (event) => {
console.log('Received event: ', JSON.stringify(event, null, 2));
if (event.request.session &&
event.request.session.length >= 3 &&
event.request.session.slice(-1)[0].challengeResult === false) {
// The user provided a wrong answer 3 times; fail auth
console.log('The user provided a wrong answer 3 times; fail auth');
event.response.issueTokens = false;
event.response.failAuthentication = true;
}
else if (event.request.session &&
event.request.session.length && event.request.session.slice(-1)[0].challengeName == "SRP_A") {
event.request.session = [];
event.response.issueTokens = false;
event.response.failAuthentication = false;
event.response.challengeName = 'CUSTOM_CHALLENGE';
}
else if (event.request.session &&
event.request.session.length &&
event.request.session.slice(-1)[0].challengeName === 'CUSTOM_CHALLENGE' &&
event.request.session.slice(-1)[0].challengeResult === true) {
// The user provided the right answer; succeed auth
console.log('The user provided the right answer; succeed auth');
event.response.issueTokens = true;
event.response.failAuthentication = false;
}
else {
// The user did not provide a correct answer yet; present challenge
console.log('The user did not provide a correct answer yet; present challenge');
event.response.issueTokens = false;
event.response.failAuthentication = false;
event.response.challengeName = 'CUSTOM_CHALLENGE';
}
console.log('Returned event: ', JSON.stringify(event, null, 2));
return event;
};
Hello @dmennis
Thanks a lot for your time!
I updated the lambda function and I don't see the crash anymore, but my iOS app returns an error in the login sequence, this one:
Printing description of error:
▿ Optional<Error>
▿ some : AWSMobileClientError
▿ userLambdaValidation : 1 element
- message : "CreateAuthChallenge failed with error Cannot read property \'match\' of null."
(lldb)
Checking CloudWatch, I see that CreateAuthChallenge is failing:
2019-12-12T14:42:37.910Z bd6d5984-6fe6-4cc3-9d27-eae73597e106
{
"errorMessage": "Cannot read property 'match' of null",
"errorType": "TypeError",
"stackTrace": [
"exports.handler (/var/task/create-auth-challenge.js:30:63)"
]
}
This is line 30:
secretLoginCode = previousChallenge.challengeMetadata.match(/CODE-(\d*)/)[1];
Any idea? Perhaps it is related with my logic. What logic do you apply? In my case, I run login after (inside) I run signup? Is that right? Should I use the same password? What about if the user already signed up, what password should I use?
Can I see your source code to play with it?
Thank you, I appreciate your help
@Ricardo1980
I had so many tweaks in my Lambda functions that I needed to clean up. I believe this should work for you. Leaving your iOS client code alone (for now), only update your DefineAuthChallenge and CreateAuthChallenge functions with the updated code below. I should have the mobile client code available in a couple days. Please let me know if this works for you. Still needs some cleanup but this flow is sweet once it's implemented.
DefineAuthChallenge Lambda function (Node.js):
https://gist.github.com/mobilequickie/f4b4da3e42ae49d2306156ba3a9eaa75
CreateAuthChallenge Lambda function (Node.js):
https://gist.github.com/mobilequickie/202a7dd1f72a2440b140f9bf44e6e46f
-Dennis
@mobilequickie
Thanks a lot Dennis!
I am going to try that once I get home.
Do you know if AWS will sooner or later support this flow officially? (passwordless login using Cognito)
Thanks!
Hello Dennis, (@mobilequickie @dmennis )
It is working and works perfectly! Thank you very much for your help!
Just 3 questions:
Can you confirm the logic I am using is OK? Firstly I call AWSMobileClient.default().signUp, if I receive confirmed or userAlreadyExists, then I call AWSMobileClient.default().signIn, Any other case, show error. Later, I call AWSMobileClient.default().confirmSignIn(challengeResponse: code) and the state changes to signedIn, which is good!
Is that OK?
There is something I don't understand, it does not not matter if I use a different password in the signup method and later in the signIn method. Does this mean it does not matter? Reading this:
https://aws.amazon.com/blogs/mobile/customizing-your-user-pool-authentication-flow/
"Name of the next challenge. For example, possible values can be CUSTOM_CHALLENGE, if a custom challenge needs to be answered, or PASSWORD_VERIFIER, if password verification is required."
Appears that mean the password can be completely ignored by Cognito when using CUSTOM_AUTH?
To resend the code (very often we have that option), should I call signIn again?
I don't think AWSMobileClient.default().resendSignUpCode is what I need.
Thanks a lot!
Hi @Ricardo1980
- Can you confirm the logic I am using is OK? Firstly I call AWSMobileClient.default().signUp, if I receive confirmed or userAlreadyExists, then I call AWSMobileClient.default().signIn, Any other case, show error. Later, I call AWSMobileClient.default().confirmSignIn(challengeResponse: code) and the state changes to signedIn, which is good!
Is that OK?
Yes, looks good to me.
Appears that mean the password can be completely ignored by Cognito when using CUSTOM_AUTH?
AWSMobileClient assumes that the first step of custom auth as username/password. So you have to provide a value for username and password when you invoke signIn. But for passwordless flow, the password provided is ignored by Cognito.
- To resend the code (very often we have that option), should I call signIn again?
I don't think AWSMobileClient.default().resendSignUpCode is what I need.
AWSMobileClient does not support resending signIn code for a custom auth flow. Anything involved in your custom auth flow would need to be handled by your code, so if you want to resend a sign in code to your user, you’ll have to handle that. It’s feasible that you could do it within an existing custom auth session, but the cleanest way to do it would be to call signIn again.
@royjit Thank you.
I'm going to follow your recommendation and call signIn again.
BTW, do you see a security problem regarding sending the sms again and again?
What about if the user calls signIn every single second? Probably my AWS bill would be very high.
I could add a timer in the user interface and avoid this problem, but any clever hacker could bypass this. How should I modify the lambda functions to add add a timer and avoid this potential problem? Any recommendation?
And last question, what about if I user tells me that for any reason he does not receive the sms message? How could on-board this user manually (using cognito console)? This should be done only in exceptional cases.
Thanks a lot for your help.
Thanks for all the comments & examples on this issue, helped us solve the similar problem 👍
@royjit do you have any timeline when this would be fixed in the SDK itself? Meaning having CUSTOM_CHALLENGE as the challengeName instead of SRP_A?
Just published the iOS Sample App with CUSTOM_AUTH using the latest SDK as part of the "amplify-passwordless-sms-auth" Serverless Application.
Serverless Repository Application
Source Code (Backend)
Source Code (iOS Client)
@jukra This will be picked up soon, but I do not have an ETA.
@dmennis Thank you for the providing the samples
This issue has been automatically closed because of inactivity. Please open a new issue if are still encountering problems.
When wrong user login ios app is crashing and no log displayed. But in Android is working with out crash. Why?
check this
Most helpful comment
Just published the iOS Sample App with CUSTOM_AUTH using the latest SDK as part of the "amplify-passwordless-sms-auth" Serverless Application.
Serverless Repository Application
Source Code (Backend)
Source Code (iOS Client)