Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Auth.SignIn() with Custom_Auth not returning NewDeviceMetadata #12220

Closed
3 tasks done
aaamoshd opened this issue Oct 6, 2023 · 8 comments
Closed
3 tasks done

Auth.SignIn() with Custom_Auth not returning NewDeviceMetadata #12220

aaamoshd opened this issue Oct 6, 2023 · 8 comments
Assignees
Labels
Auth Related to Auth components/category investigating This issue is being investigated

Comments

@aaamoshd
Copy link

aaamoshd commented Oct 6, 2023

Before opening, please confirm:

JavaScript Framework

React

Amplify APIs

Authentication

Amplify Categories

auth

Environment information

 System:
    OS: Windows 10 10.0.22621
    CPU: (8) x64 11th Gen Intel(R) Core(TM) i7-11370H @ 3.30GHz
    Memory: 2.68 GB / 15.74 GB
  Binaries:
    Node: 20.5.1 - C:\Program Files\nodejs\node.EXE
    Yarn: 1.22.11 - ~\AppData\Roaming\npm\yarn.CMD
    npm: 9.8.0 - C:\Program Files\nodejs\npm.CMD
  Browsers:
    Edge: Chromium (117.0.2045.47)
    Internet Explorer: 11.0.22621.1
  npmPackages:
    @aws-amplify/ui-react: ^5.3.1 => 5.3.1
    @aws-amplify/ui-react-internal:  undefined ()
    @testing-library/jest-dom: ^5.17.0 => 5.17.0
    @testing-library/react: ^13.4.0 => 13.4.0
    @testing-library/user-event: ^13.5.0 => 13.5.0
    @types/jest: ^27.5.2 => 27.5.2
    @types/node: ^16.18.55 => 16.18.55
    @types/react: ^18.2.23 => 18.2.23
    @types/react-dom: ^18.2.8 => 18.2.8
    aws-amplify: ^5.3.11 => 5.3.11
    env-cmd: ^10.1.0 => 10.1.0
    localforage: ^1.10.0 => 1.10.0
    match-sorter: ^6.3.1 => 6.3.1
    react: ^18.2.0 => 18.2.0
    react-dom: ^18.2.0 => 18.2.0
    react-router-dom: ^6.16.0 => 6.16.0
    react-scripts: 5.0.1 => 5.0.1
    sort-by: ^1.2.0 => 1.2.0
    typescript: ^4.9.5 => 4.9.5
    web-vitals: ^2.1.4 => 2.1.4
  npmGlobalPackages:
    corepack: 0.19.0
    npm: 9.8.0

Describe the bug

When using CUSTOM_AUTH flow in Amplify SDK for React, even on a new device after PASSWORD_VERIFIER no NewDeviceMetadata is sent back thus preventing from marking the logged in device as remembered. User Pool has Device Tracking set to Always.

After a successful issuance of tokens when trying to perform

await Auth.rememberDevice()

I am getting "Device tracking has not been configured in this user pool" which is also a little misleading enum description used for all errors with DeviceKey not found

Expected behavior

Cognito to send NewDeviceMetadata when no DeviceKey is sent on the initial sign in request.

Reproduction steps

  1. Install Amplify SDK for React 5.3.1
  2. Configure Amplify to work with custom auth flow
Amplify.configure({
  Auth: {
   region: process.env.REACT_APP_COGNITO_REGION,
   userPoolId: process.env.REACT_APP_COGNITO_POOL_ID,
   userPoolWebClientId: process.env.REACT_APP_COGNITO_CLIENT_ID,
   authenticationFlowType: 'CUSTOM_AUTH'
  }
} as AmplifyConfiguration);
  1. Initiate Login
await Auth.signIn(username, password).then((res) =>{
       if(res.challengeName === "USER_SRP_AUTH"){
           await Auth.rememberDevice(); // Error -> Invalid device key
       }
      else if(res.challengeName === "CUSTOM_CHALLENGE"){
           .....        
      }
});

Code Snippet

await Auth.signIn(username, password).then((res) =>{
       if(res.challengeName === "USER_SRP_AUTH"){
           await Auth.rememberDevice(); // Error -> Invalid device key
       }
      else if(res.challengeName === "CUSTOM_CHALLENGE"){
           .....        
      }
});

Log output

[DEBUG] 51:49.72 AuthClass CognitoUserSession {idToken: CognitoIdToken, refreshToken: CognitoRefreshToken, accessToken: CognitoAccessToken, clockDrift: 3}
ConsoleLogger.js:122 [DEBUG] 51:49.72 Credentials - removing aws-amplify-federatedInfo from storage
ConsoleLogger.js:122 [DEBUG] 51:49.73 Credentials - set credentials from session
ConsoleLogger.js:122 [DEBUG] 51:49.73 Credentials - No Cognito Federated Identity pool provided
ConsoleLogger.js:134 [DEBUG] 51:49.73 AuthClass - cannot get cognito credentials No Cognito Federated Identity pool provided
ConsoleLogger.js:134 [DEBUG] 51:49.74 AuthClass - Succeed to get the user session CognitoUserSession {idToken: CognitoIdToken, refreshToken: CognitoRefreshToken, accessToken: CognitoAccessToken, clockDrift: 3}accessToken: CognitoAccessToken {jwtToken: 'XXXX', payload: {…}}clockDrift: 3idToken: CognitoIdToken {jwtToken: 'XXXX', payload: {…}}refreshToken: CognitoRefreshToken {token: 'XXXX'}[[Prototype]]: Object
ConsoleLogger.js:134 [DEBUG] 51:49.270 Hub - Dispatching to auth with  {event: 'signIn', data: CognitoUser, message: 'A user XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX has been signed in'}data: CognitoUserSession: nullattributes: {}authenticationFlowType: "USER_SRP_AUTH"client: Client {endpoint: 'https://cognito-idp.us-east-1.amazonaws.com/', fetchOptions: {…}}keyPrefix: "CognitoIdentityServiceProvider.XXXX"pool: CognitoUserPool {userPoolId: 'us-east-XXXX', clientId: 'XXXX', client: Client, advancedSecurityDataCollectionFlag: true, storage: Storage, …}preferredMFA: "XXX"signInUserSession: CognitoUserSession {idToken: CognitoIdToken, refreshToken: CognitoRefreshToken, accessToken: CognitoAccessToken, clockDrift: 3}storage: Storage {CognitoIdentityServiceProvider.XXXX.XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX.idToken: 'XXXXX', CognitoIdentityServiceProvider.XXX.XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX.accessToken: 'XXXX', CognitoIdentityServiceProvider.XXX.XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX.clockDrift: '3', CognitoIdentityServiceProvider.XXX.XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX.userData: '{"UserAttributes":[{}', amplify-signin-with-hostedUI: 'false', …}userDataKey: "CognitoIdentityServiceProvider.XXXX.XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX.userData"username: "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX"[[Prototype]]: Objectevent: "signIn"message: "A user XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX has been signed in"[[Prototype]]: Object
ConsoleLogger.js:134 [DEBUG] 51:49.279 AuthClass - Succeed to get the user session CognitoUserSession {idToken: CognitoIdToken, refreshToken: CognitoRefreshToken, accessToken: CognitoAccessToken, clockDrift: 3}
Client.js:102     POST https://cognito-idp.us-east-1.amazonaws.com/ 400 (Bad Request)
request @ Client.js:102
setDeviceStatusRemembered @ CognitoUser.js:1511
(anonymous) @ Auth.ts:2715
(anonymous) @ Auth.ts:2714
step @ tslib.es6.js:100
(anonymous) @ tslib.es6.js:81
fulfilled @ tslib.es6.js:71
Promise.then (async)
step @ tslib.es6.js:73
(anonymous) @ tslib.es6.js:74
__awaiter @ tslib.es6.js:70
AuthClass.rememberDevice @ Auth.ts:2703
(anonymous) @ App.tsx:48
(anonymous) @ App.tsx:49
commitHookEffectListMount @ react-dom.development.js:23150
commitPassiveMountOnFiber @ react-dom.development.js:24926
commitPassiveMountEffects_complete @ react-dom.development.js:24891
commitPassiveMountEffects_begin @ react-dom.development.js:24878
commitPassiveMountEffects @ react-dom.development.js:24866
flushPassiveEffectsImpl @ react-dom.development.js:27039
flushPassiveEffects @ react-dom.development.js:26984
(anonymous) @ react-dom.development.js:26769
workLoop @ scheduler.development.js:266
flushWork @ scheduler.development.js:239
performWorkUntilDeadline @ scheduler.development.js:533
ConsoleLogger.js:122 [ERROR] 51:49.370 AuthError - Device tracking has not been configured in this User Pool
ConsoleLogger._log @ ConsoleLogger.js:122
ConsoleLogger.error @ ConsoleLogger.js:205
AuthError @ Errors.ts:24
onFailure @ Auth.ts:2721
(anonymous) @ CognitoUser.js:1517
(anonymous) @ Client.js:127
Promise.then (async)
request @ Client.js:116
setDeviceStatusRemembered @ CognitoUser.js:1511
(anonymous) @ Auth.ts:2715
(anonymous) @ Auth.ts:2714
step @ tslib.es6.js:100
(anonymous) @ tslib.es6.js:81
fulfilled @ tslib.es6.js:71
Promise.then (async)
step @ tslib.es6.js:73
(anonymous) @ tslib.es6.js:74
__awaiter @ tslib.es6.js:70
AuthClass.rememberDevice @ Auth.ts:2703
(anonymous) @ App.tsx:48
(anonymous) @ App.tsx:49
commitHookEffectListMount @ react-dom.development.js:23150
commitPassiveMountOnFiber @ react-dom.development.js:24926
commitPassiveMountEffects_complete @ react-dom.development.js:24891
commitPassiveMountEffects_begin @ react-dom.development.js:24878
commitPassiveMountEffects @ react-dom.development.js:24866
flushPassiveEffectsImpl @ react-dom.development.js:27039
flushPassiveEffects @ react-dom.development.js:26984
(anonymous) @ react-dom.development.js:26769
workLoop @ scheduler.development.js:266
flushWork @ scheduler.development.js:239
performWorkUntilDeadline @ scheduler.development.js:533
Errors.ts:14 Uncaught (in promise) AuthError: Device tracking has not been configured in this User Pool
    at new AuthError (Errors.ts:14:1)
    at Object.onFailure (Auth.ts:2721:1)
    at CognitoUser.js:1517:1
    at Client.js:127:1

aws-exports.js

No response

Manual configuration

Amplify.configure({
  Auth: {
   region: process.env.REACT_APP_COGNITO_REGION,
   userPoolId: process.env.REACT_APP_COGNITO_POOL_ID,
   userPoolWebClientId: process.env.REACT_APP_COGNITO_CLIENT_ID,
   authenticationFlowType: 'CUSTOM_AUTH'
  }
} as AmplifyConfiguration);

Additional configuration

No response

Mobile Device

No response

Mobile Operating System

No response

Mobile Browser

No response

Mobile Browser Version

No response

Additional information and screenshots

{
  "name": "spa.cognito",
  "version": "0.1.0",
  "private": true,
  "dependencies": {
    "@aws-amplify/ui-react": "^5.3.1",
    "@testing-library/jest-dom": "^5.17.0",
    "@testing-library/react": "^13.4.0",
    "@testing-library/user-event": "^13.5.0",
    "@types/jest": "^27.5.2",
    "@types/node": "^16.18.55",
    "@types/react": "^18.2.23",
    "@types/react-dom": "^18.2.8",
    "aws-amplify": "^5.3.11",
    "env-cmd": "^10.1.0",
    "localforage": "^1.10.0",
    "match-sorter": "^6.3.1",
    "react": "^18.2.0",
    "react-dom": "^18.2.0",
    "react-router-dom": "^6.16.0",
    "react-scripts": "5.0.1",
    "sort-by": "^1.2.0",
    "typescript": "^4.9.5",
    "web-vitals": "^2.1.4"
  },
  "scripts": {
    "start": "env-cmd -f .env react-scripts start",
    "build": "react-scripts build",
    "test": "react-scripts test",
    "eject": "react-scripts eject"
  },
  "eslintConfig": {
    "extends": [
      "react-app",
      "react-app/jest"
    ]
  },
  "browserslist": {
    "production": [
      ">0.2%",
      "not dead",
      "not op_mini all"
    ],
    "development": [
      "last 1 chrome version",
      "last 1 firefox version",
      "last 1 safari version"
    ]
  }
}
@aaamoshd aaamoshd added the pending-triage Issue is pending triage label Oct 6, 2023
@nadetastic nadetastic added the Auth Related to Auth components/category label Oct 6, 2023
@nadetastic nadetastic self-assigned this Oct 6, 2023
@nadetastic
Copy link
Member

Hi @aaamoshd thank you for opening this issue. Since you are using Custom Auth flow, you will also need to setup any additional challenges/steps that you require.

Can you confirm that you have also setup DEVICE_SRP_AUTH flow in the custom auth lambdas?

For reference: https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_InitiateAuth.html#CognitoUserPools-InitiateAuth-response-ChallengeName

@nadetastic nadetastic added pending-response and removed pending-triage Issue is pending triage labels Oct 6, 2023
@aaamoshd
Copy link
Author

aaamoshd commented Oct 6, 2023

So does it mean that after PASSWORD_VERIFIER instead of sending to CUSTOM_CHALLENGE or resolving the authentication (in case user does not have any challenges/mfa setup) with response.issueTokens = true and response.failAuthentication = false, the custom auth definer needs to send response.challengeName as DEVICE_SRP_AUTH?

In my scneario

if (input.request.session.Count == 2 && input.request.session[1].challengeName == "PASSWORD_VERIFIER" && input.request.session[1].challengeResult == true)
{
    HandlePasswordVerifier(input);
}

private void HandlePasswordVerifier(CognitoCustomAuthEvent input) 
{
    if (input.request.userAttributes.TryGetValue("XXX", out string? abc) && !string.IsNullOrEmpty(abc) && abc== "YYY")
    {
        input.response.issueTokens = true;
        input.response.failAuthentication = false; -> instead of this do I call input.response.challengeName = "DEVICE_SRP_AUTH"?
    }
    else
    {
        input.response.issueTokens = false;
        input.response.failAuthentication = false;
        input.response.challengeName = "CUSTOM_CHALLENGE"; -> instead of this do I call input.response.challengeName = "DEVICE_SRP_AUTH"?
    }
}

I thought the DEVICE_SRP_AUTH challenge requires a DEVICE_KEY along with hash and secrets but since I am not getting the NewDeviceMetadata, I am unsure how to perform that.

@israx
Copy link
Member

israx commented Nov 10, 2023

hello @aaamoshd to have device tracking with custom-auth working, first you need to:

  • Enable device tracking in your Cognito console by picking either:
    • always : The device is remembered and there is no need to call Auth.rememberDevice
    • opt-in: You can remember a device by invoking Auth.rememberDevice
  • Configure your lambdas:
    You don't have to include DEVICE_SRP_AUTH challengeName in your lambda. I believe cognito will return it as long as the custom challenge is resolved. But You can return either SMS_MFA or SOFTWARE_TOKEN_MFA (as long as you enabled MFA in your user pool) if you want to do custom auth with MFA.

So the DEVICE_SRP_AUTH will be returned as long as the device was remembered and it is used to bypass MFA. And the library will handle it under the hood.

Take in mind that if you are using CUSTOM_AUTH you still need to answer the challenge. Device tracking is only able to bypass MFA

@israx
Copy link
Member

israx commented Nov 10, 2023

Here's a lambda that may help @aaamoshd :

export const handler = async(event) => {
 console.log(`Got request: ${JSON.stringify(event.request, null, 2)}`);
  const shouldFail = event.request.clientMetadata?.["should-fail"] === "true";
  if (shouldFail) {
    event.response.failAuthentication = true;
    event.response.issueTokens = false;
    return event;
  }
  if (
    event.request.session.length === 1 &&
    event.request.session[0].challengeName === "SRP_A"
  ) {
    event.response.issueTokens = false;
    event.response.failAuthentication = false;
    event.response.challengeName = "PASSWORD_VERIFIER";
  } else if (
    event.request.session.length === 2 &&
    event.request.session[1].challengeName === "PASSWORD_VERIFIER" &&
    event.request.session[1].challengeResult === true
  ) {
    event.response.issueTokens = false;
    event.response.failAuthentication = false;
    event.response.challengeName = "CUSTOM_CHALLENGE";
  } else if (
    event.request.session.length === 3 &&
    event.request.session[2].challengeName === "CUSTOM_CHALLENGE" &&
    event.request.session[2].challengeResult === true
  ) {
    event.response.failAuthentication = false;
    event.response.issueTokens = true;
  } else if (
    event.request.session.length === 3 &&
    event.request.session[2].challengeName === "SMS_MFA" &&
    event.request.session[2].challengeResult === true
    ){
    event.response.issueTokens = false;
    event.response.failAuthentication = false;
    event.response.challengeName = "CUSTOM_CHALLENGE";
  }else if (
    event.request.session.length === 3 &&
    event.request.session[2].challengeName === "SOFTWARE_TOKEN_MFA" &&
    event.request.session[2].challengeResult === true
    ){
    event.response.issueTokens = false;
    event.response.failAuthentication = false;
    event.response.challengeName = "CUSTOM_CHALLENGE";
    }else if (
    event.request.session.length === 4 &&
    event.request.session[3].challengeName == "CUSTOM_CHALLENGE" &&
    event.request.session[3].challengeResult == true
  ) {
    event.response.issueTokens = true;
    event.response.failAuthentication = false;
  }else {
    event.response.issueTokens = false;
    event.response.failAuthentication = true;
  }
  return event;
    
};

@nadetastic
Copy link
Member

HI @aaamoshd following up here, did the above comments from @israx help to get you unblocked?

@nadetastic
Copy link
Member

Hi @aaamoshd - closing out this issue. Let me know if you have any more questions.

@travefymcarino
Copy link

@nadetastic - I just wanted to follow up as I am seeing the same behavior as @aaamoshd. There seems to be a separate conversation #11833 (comment) which reported this issue as a known area in need of improvement.

I have followed the recommendations of @israx and am still running into problems with NewDeviceMetadata not being returned in CUSTOM_AUTH flows. I am hoping to gain clarification on whether this issue is resolved.

@israx
Copy link
Member

israx commented Jan 5, 2024

hello @travefymcarino , are you seeing that behavior while using amplify-js v6?

You can also open a new ticket, so we can keep track of your issue.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Auth Related to Auth components/category investigating This issue is being investigated
Projects
None yet
Development

No branches or pull requests

4 participants