aws-amplify / aws-sdk-android

AWS SDK for Android. For more information, see our web site:
https://docs.amplify.aws
Other
1.03k stars 550 forks source link

Android cognito passwordless sign-in #1160

Closed MichalCR closed 5 years ago

MichalCR commented 5 years ago

State your question Hi,

I'm trying to use cognito passwordless sign-in feature. I follow this example: https://aws.amazon.com/blogs/mobile/implementing-passwordless-email-authentication-with-amazon-cognito/ and deployed lambda functions. I'm able to register the user but when I'm trying to login him using this method:

AWSMobileClient.getInstance().signIn("<email>", "<password>", null, new Callback<SignInResult>() {});

I'm getting following error:

com.amazonaws.services.cognitoidentityprovider.model.InvalidParameterException: Only custom auth (lambda driven) is enabled for this client. (Service: AmazonCognitoIdentityProvider; Status Code: 400; Error Code: InvalidParameterException; Request ID: ...)

Can you please tell how to sign-in the user to Cognito via Android Amplify SDK when I'm using lambda functions.

Which AWS Services are you utilizing? Amazon Cognito

Provide code snippets (if applicable) AWSMobileClient.getInstance().signIn("<email>", "<password>", null, new Callback<SignInResult>() {});

Environment(please complete the following information):

Device Information (please complete the following information):

desokroshan commented 5 years ago

@MichalCR Thanks for reaching out. AWSMobileClient currently does not support Cognito custom authentication flow. I am actively working on it and although I do not have a firm timeline for you I expect it to be released in near future. In the meanwhile if you have an urgent requirement you can Cognito Userpools SDK as follows to implement the Passwordless login :


    // Userpool
    private CognitoUserPool cup;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
       // Instantiate Cognito User Pool
        cup = new CognitoUserPool(getApplicationContext(), new AWSConfiguration(getApplicationContext()));
        cup.getCurrentUser().signOut();
        //signUp();
        // Call Sign in
         signIn();
    }

    private void signIn() {
        AuthenticationHandler authenticationHandler = new AuthenticationHandler() {
            @Override
            public void onSuccess(CognitoUserSession userSession, CognitoDevice newDevice) {
                Log.d(TAG, "Signed in Successfully");
                Log.d(TAG, userSession.getAccessToken().toString());
                Log.d(TAG, userSession.getIdToken().toString());

            }

            @Override
            public void getAuthenticationDetails(AuthenticationContinuation authenticationContinuation, String userId) {
                Log.d(TAG, "getAuthenticationDetails called. ");
                final HashMap<String, String> authParameters = new HashMap<>();
                AuthenticationDetails authenticationDetails = new AuthenticationDetails(username, password, authParameters, null);
                authenticationContinuation.setAuthenticationDetails(authenticationDetails);
                authenticationContinuation.continueTask();
            }

            @Override
            public void getMFACode(MultiFactorAuthenticationContinuation continuation) {
                // This will not be called in my use case
            }

            @Override
            public void authenticationChallenge(ChallengeContinuation continuation) {
                Log.d(TAG, "authenticationChallenge called.");
                continuation.setChallengeResponse(CognitoServiceConstants.CHLG_RESP_ANSWER, "1133");
                continuation.continueTask();
            }

            @Override
            public void onFailure(Exception exception) {
                Log.e(TAG, "onFailure called", exception);
            }
        };

       // cup -> Cognito User Pool object
        cup.getUser(username).getSessionInBackground(authenticationHandler);

    }

Hope that helps. Let me know if you have any questions.

MichalCR commented 5 years ago

Hi @desokroshan,

THX for your response! I checked your snipped today and I noticed very weird behavior. When I'm invoking signIn method then application invokes getAuthenticationDetails callback and right after that onSuccess with accessToken and idToken. User has logged in right away without the need of providing sign-in code from the email. In fact, I did not get any email with code.

Please correct me if I'm wrong but as per flow presented in a passwordless example: https://aws.amazon.com/blogs/mobile/implementing-passwordless-email-authentication-with-amazon-cognito/, after getAuthenticationDetails Cognito should send an email with secure code. Then this secure code should be used in authenticationChallenge callback.

Here are logs that I'm getting from Cognito when I'm invoking signIn method.

Capturing and displaying logcat messages from application. This behavior can be disabled in the "Logcat output" section of the "Debugger" settings page.
W/CognitoUserSession: CognitoUserSession is not valid because idToken is null.
D/TAG: getAuthenticationDetails called. 
D/NetworkSecurityConfig: No Network Security Config specified, using platform default
V/com.amazonaws.request: Parsing service response JSON
D/com.amazonaws.request: CRC32Checksum = null
    content encoding = null
V/com.amazonaws.request: Done parsing service response
I/AWSKeyValueStore: Detected Android API Level = 28
    Creating the AWSKeyValueStore with key for sharedPreferencesForData = CognitoIdentityProviderDeviceCache.<pool_id>
D/KeyProvider23: AndroidKeyStore contains keyAlias CognitoIdentityProviderCache.aesKeyStoreAlias
    Loading the encryption key from Android KeyStore.
D/KeyProvider23: AndroidKeyStore contains keyAlias CognitoIdentityProviderCache.aesKeyStoreAlias
    Loading the encryption key from Android KeyStore.
D/KeyProvider23: AndroidKeyStore contains keyAlias CognitoIdentityProviderCache.aesKeyStoreAlias
    Loading the encryption key from Android KeyStore.
D/KeyProvider23: AndroidKeyStore contains keyAlias CognitoIdentityProviderCache.aesKeyStoreAlias
    Loading the encryption key from Android KeyStore.
D/TAG: Signed in Successfully
    com.amazonaws.mobileconnectors.cognitoidentityprovider.tokens.<access_token>
    com.amazonaws.mobileconnectors.cognitoidentityprovider.tokens.<id_token>

Could you please tell why I might not get sign-in code on email?

desokroshan commented 5 years ago

@MichalCR Were you able to resolve the issue?

SubirZ commented 5 years ago

Hi @desokroshan, I am trying to implement the passwordless signIn, but in the Android mobile SDK sign-in method has a mandatory password field, on providing null/""(blank) password it throws an error.

for blank password:"" Sign-in errorIncorrect username or password. (Service: AmazonCognitoIdentityProvider; Status Code: 400; Error Code: NotAuthorizedException; Request ID: 47494e68-687c-4eb1-aae3-8c2a3a886355)

for null password:null Sign-in errorFailed to find password in authentication details to response to PASSWORD_VERIFIER challenge.

Is there any way to fix this.

LinearLogic commented 5 years ago

For anyone running into this, @desokroshan's snippet works like a charm, just not with the authflow lambdas deployed by the Serverless App referenced in the blog post @MichalCR mentioned. I was able to tweak the DefineAuthChallenge and CreateAuthChallenge lambdas to achieve OTP auth on Android without breaking existing OTP auth on iOS/ReactNative.

Here's a gist with the lambdas I'm using. I've commented the substantive changes to the Serverless App lambdas (just one line in each) to document the ways in which the Android SDK's behavior diverges from the Javascript SDK, to the best of my limited knowledge. Hopefully this helps others keep what remains of their hair and get back to hacking.

desokroshan commented 5 years ago

@SubirZ We have released support for passwordless sign in MobileClient in 2.16.0. You can find documentation here. You can pass a dummy password and should not run into error. Please give it a try and let me know if you see issues?

desokroshan commented 5 years ago

@LinearLogic Yeah the lambdas in blog post does not work. You can use Amplify CLI to get lambda templates that you can then use to tweak to meet your use case. https://aws-amplify.github.io/docs/cli-toolchain/cognito-triggers

tomsterritt commented 5 years ago

@desokroshan I'm also trying to use custom auth flow, using 2.16.0 and similar lambda as the gist above and passing a dummy password, however I get the error: Auth signIn error USER_SRP_AUTH is not enabled for the client. (Service: AmazonCognitoIdentityProvider; Status Code: 400; Error Code: InvalidParameterException; Request ID:...

ximenaperez commented 4 years ago

I'm getting the same error as @tomsterritt , did you find out what the problem was? @desokroshan

RaviTh450 commented 1 year ago

there is no proper documentation on this from last 3 days just exploring and exploring can anyone ??

banji180 commented 1 year ago

@BilliDevs we don’t currently support passwordless out of the box.

tylerjroach commented 1 year ago

@BilliDevs It looks like some of the links in this issue are out of date. Have you taken a look at https://docs.amplify.aws/lib/auth/signin_with_custom_flow/q/platform/android/?