aws / aws-sdk-net-extensions-cognito

An extension library to assist in the Amazon Cognito User Pools authentication process
Apache License 2.0
102 stars 49 forks source link

Unable to re-authenticate (not refresh) using the same device key #139

Closed alfarok closed 4 months ago

alfarok commented 5 months ago

Describe the bug

I am attempting to use the aws-sdk-net-extensions-cognito library for Cognito authentication with device tracking enabled. The cloud formation properties on the User Pool for this configuration are:

DeviceConfiguration:
    ChallengeRequiredOnNewDevice: false
    DeviceOnlyRememberedOnUserPrompt: false

I can successfully complete the following steps:

My issue at this point is that signing out and attempting to sign back in fails using the device key from the previous session. I know I need to generate a new token but I shouldn't have to regenerate the device key on the same device. Currently, when I tried to login using the device key from the previous session I get the following error:

"Incorrect username or password."

Here is my code for attempting to login using a local device key from the previous session:

user.Device = new CognitoDevice(
    new DeviceType { DeviceKey = deviceKey },
    user
);

var deviceVerifier = user.GenerateDeviceVerifier(DeviceInfo.DeviceGroupKey, password, DeviceInfo.DeviceKey);

authRequest = new InitiateSrpAuthRequest()
{
    Password = password,
    DeviceGroupKey = deviceGroupKey,
    DevicePass = deviceVerifier.PasswordVerifier,
    DeviceVerifier = deviceVerifier.Salt
};

// Fails with 400 error mentioned above
var authResponse = await user.StartWithSrpAuthAsync(authRequest);

I have a feeling it's related to the creation of new InitiateSrpAuthRequest() and the values I am providing. I was unable to find documentation around these parameter values. I was assuming DevicePass is the PasswordVerifier created by GenerateDeviceVerifier and DeviceVerifier is the Salt from GenerateDeviceVerifier but the key names are confusing?

TLDR: What values are expected for DevicePass and DeviceVerifier or am I doing something else incorrectly?

Expected Behavior

I can re-authenticate a user (not refresh) but use the same device key which will not create a new device for that user as long as they are on the same machine.

Current Behavior

AWS .NET SDK and/or Package version used

Amazon.Extensions.CognitoAuthentication 2.5.2 (latest)

Targeted .NET Platform

.NET Framework 4.8 & .NET 6.0

Operating System and version

Windows 10/11

alfarok commented 5 months ago

The issue follows a very similar flow outlined in this other old issue https://github.com/aws/aws-sdk-net-extensions-cognito/issues/44 but I am getting a different error at the final step.

Another user on the same thread commented with the SAME ERROR message but his remedy did not seem to help me. He is questioning the signature on GenerateDeviceVerifier(). I have tried username and deviceKey.

alfarok commented 4 months ago

Hi @bhoradc, were you able to reproduce the issue or do you need any additional information? Thanks!

alfarok commented 4 months ago

Hey @96malhar @ashishdhingra, do you know if this repo is being actively maintained or if I should be using a different AWS API for this?

bhoradc commented 4 months ago

Hi @alfarok,

Apologies for some silence here. I haven't got a chance to work on this one yet. I plan to work on reproducing it during this week. And will get back to you with further update or if any information is needed. Thank you.

-->update - I have started working on the repro code for this one, hopefully will complete and have some update soon.

Regards, Chaitanya

bhoradc commented 4 months ago

Hello @alfarok,

Can you check if setting DevicePass = password works in your case?

authRequest = new InitiateSrpAuthRequest()
{
    Password = password,
    DeviceGroupKey = deviceGroupKey,
    DevicePass = password,
    DeviceVerifier = deviceVerifier.Salt
};

Regards, Chaitanya

alfarok commented 4 months ago

Thank you @bhoradc, I am able to re-authenticate now without creating a new device entry. I swear I thought I tried that combo but also refactored my logic from my original attempts so could have been a combination of things. Really appreciate your follow-up and assistance.

For anyone else that comes across this ->

A login attempt where no device key is present must use something similar to this:

// Initialize first login
InitiateSrpAuthRequest authRequest = new InitiateSrpAuthRequest() { Password = password};
// Login
AuthFlowResponse authResponse = await User.StartWithSrpAuthAsync(authRequest).ConfigureAwait(true);
// Extract device metadata
var md = authResponse.AuthenticationResult.NewDeviceMetadata;
// Generate a verifier
var deviceVerifier = User.GenerateDeviceVerifier(md.DeviceGroupKey, password, md.DeviceKey);
// Confirm device
 var confirmDeviceResponse = await User.ConfirmDeviceAsync(AccessToken, md.DeviceKey, DeviceName, DeviceVerifier.PasswordVerifier, DeviceVerifier.Salt);

Attempts where an existing device key is present should use something like this:

// Generate a verifier with cached device data
var deviceVerifier = User.GenerateDeviceVerifier(deviceGroup, password, deviceKey);
// Initialize subsequent logins while cache is present
InitiateSrpAuthRequest authRequest = new InitiateSrpAuthRequest()
{
    Password = password,
    DeviceGroupKey = deviceGroup,
    DevicePass = password,
    DeviceVerifier = deviceVerifier.Salt
};
// Login
AuthFlowResponse authResponse = await User.StartWithSrpAuthAsync(authRequest).ConfigureAwait(true);
github-actions[bot] commented 4 months ago

⚠️COMMENT VISIBILITY WARNING⚠️

Comments on closed issues are hard for our team to see. If you need more assistance, please either tag a team member or open a new issue that references this one. If you wish to keep having a conversation with other community members under this issue feel free to do so.