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

Device metadata is being deleted when using default storage as session storage #14135

Open
3 tasks done
2-Dpot opened this issue Jan 13, 2025 · 7 comments
Open
3 tasks done
Assignees
Labels
Auth Related to Auth components/category pending-community-response Issue is pending a response from the author or community. question General question

Comments

@2-Dpot
Copy link

2-Dpot commented Jan 13, 2025

Before opening, please confirm:

JavaScript Framework

Angular

Amplify APIs

Authentication

Amplify Version

v6

Amplify Categories

No response

Backend

Other

Environment information

# Put output below this line

System:
 * OS: Windows 11 10.0.22621
 * CPU: (4) x64 Intel(R) Xeon(R) Platinum 8375C CPU @ 2.90GHz
 * Memory: 15.84 GB / 64 GB
Binaries:
 * Node: 18.19.1  (C:\Program Files\nodejs\node.exe)
 * npm: 10.2.4 (C:\Program Files\nodejs\npm.CMD)
Browsers:
 * Edge: Chromium (131.0.2903.112)
 * Internet Explorer: 11.0.22621.3527
npmPackages:
 * @angular-devkit/build-angular: ^17.3.6  → 17.3.8
 * @angular-eslint/builder: "17.3.0" → 17.5.2
 * @angular-eslint/eslint-plugin: "17.3.0" → 17.5.2
 * @angular-eslint/eslint-plugin-template: "17.3.0" → 17.5.2
 * @angular-eslint/schematics: 17.3.0 → 17.5.2
 * @angular-eslint/template-parser: "17.3.0" → 17.5.2
 * @angular/animations: 17.3.7 → 17.3.12
 * @angular/cdk: 17.3.7 → 17.3.10
 * @angular/cli: 17.3.6 → 17.3.8
 * @angular/common: 17.3.7 → 17.3.12
 * @angular/compiler: 17.3.7 → 17.3.12
 * @angular/compiler-cli: 17.3.7 → 17.3.12
 * @angular/compiler/testing:  undefined  (15.0.0)
 * @angular/core: 17.3.7 → 17.3.12  (15.0.0)
 * @angular/core/testing: undefined (15.0.0)
 * @angular/forms: 17.3.7 → 17.3.12
 * @angular/language-service: 17.3.7 → 17.3.12
 * @angular/platform-browser: 17.3.7 → 17.3.12
 * @angular/platform-browser-dynamic: 17.3.7 → 17.3.12
 * @angular/router: 17.3.7 → 17.3.12
 * @fortawesome/fontawesome-free: 6.2.1 → 6.6.0
 * @ng-bootstrap/ng-bootstrap: 16.0.0 → 16.0.0
 * @ng-idle/core: 14.0.0 → 14.0.0
 * @ng-idle/keepalive: 14.0.0 → 14.0.0
 * @okta/okta-angular: 6.0.0 → 6.4.0
 * @okta/okta-auth-js: 7.2.0 → 7.7.1
 * @popperjs/core: 2.11.2 → 2.11.8
 * @types/crypto-js: 3.1.47 → 3.1.47 (already at latest)
 * @types/file-saver: 2.0.5 → 2.0.7
 * @types/jasmine: 4.3.1 → 4.6.4
 * @types/jasminewd2: 2.0.10 → 2.0.13
 * @types/jquery: ^3.5.16 → 3.5.30
 * @types/node: 18.11.18 → 18.19.45
 * @typescript-eslint/eslint-plugin: ^7.2.0 → 7.18.0
 * @typescript-eslint/parser: 7.2.0 → 7.18.0
 * angular-disable-browser-back-button: ^2.0.0 → 2.0.0 (already at latest)
 * aws-amplify: ^6.2.0 = 6.5.2
 * aws-amplify/adapter-core: undefined
 * aws-amplify/analytics: undefined
 * aws-amplify/analytics/kinesas: undefined
 * aws-amplify/analytics/kinesis-firehose: undefined
 * aws-amplify/analytics/personalize: undefined
 * aws-amplify/analytics/pinpoint: undefined
 * aws-amplify/api: undefined
 * aws-amplify/api/server: undefined
 * aws-amplify/auth: undefined
 * aws-amplify/auth/cognito: undefined
 * aws-amplify/auth/cognito/server: undefined
 * aws-amplify/auth/enable-cauth-listener: undefined
 * aws-amplify/auth/server: undefined
 * aws-amplify/data: undefined
 * aws-amplify/data/server: undefined
 * aws-amplify/datastore: undefined
 * aws-amplify/in-app-messaging: undefined
 * aws-amplify/in-app-messaging/pinpoint: undefined
 * aws-amplify/push-notifications: undefined
 * aws-amplify/push-notifications/pinpoint: undefined
 * aws-amplify/storage: undefined
 * aws-amplify/storage/s3: undefined
 * aws-amplify/storage/s3/server: undefined
 * aws-amplify/storage/server: undefined
 * aws-amplify/utils: undefined
 * babel-polyfill: 6.26.0 → 6.26.0 (already at latest)
 * bootstrap: 5.2.3 → 5.3.3
 * codelyzer: ^6.0.2 → 6.0.2 (already at latest)
 * crypto-js: 4.1.1 → 4.2.0
 * css-vars-ponyfill: 2.4.8 → 2.4.9
 * eslint: 8.57.0 → 8.57.0 (already at latest)
 * example-typescript: 1.0.0
 * file-saver: 2.0.5 → 2.0.5 (already at latest)
 * hammerjs: ^2.0.8 → 2.0.8 (already at latest)
 * highcharts: ^10.3.2 → 10.3.3
 * jasmine-core: ^4.5.0 → 4.6.1 (2.8.0)
 * jasmine-spec-reporter: ^7.0.0 → 7.0.0 (already at latest)
 * jquery: 3.6.3 → 3.7.1
 * jspdf: 2.5.1 → 2.5.1 (already at latest)
 * jspdf-autotable: 3.6.0 → 3.8.2
 * karma: 6.4.1 → 6.4.4
 * karma-chrome-launcher: ^3.1.1 → 3.2.0
 * karma-coverage: 2.2.0 → 2.2.1
 * karma-coverage-coffee-example: 1.0.0
 * karma-jasmine: 5.1.0 → 5.1.0 (already at latest)
 * karma-jasmine-html-reporter: ^2.0.0 → 2.1.0
 * moment: 2.29.4 → 2.30.1
 * ng2-pdfjs-viewer: ^17.0.3 → 17.0.4
 * ngx-daterangepicker-material: 6.0.4 → 6.0.4 (already at latest)
 * ngx-mask: ^15.0.2 → 15.2.3
 * node-example: 1.0.0
 * popper.js: ^1.16.1 → 1.16.1 (already at latest)
 * primeicons: ^7.0.0 → 7.0.0 (already at latest)
 * primeng: 17.16.0 → 17.16.0 (already at latest)
 * promise-polyfill: 8.2.3 → 8.3.0
 * protractor: ~7.0.0 → 7.0.0 (already at latest)
 * protractor-example: 1.0.0
 * purecloud-platform-client-v2: ^156.0.0 → 156.0.0 (already at latest)
 * roboto-fontface: ^0.10.0 → 0.10.0 (already at latest)
 * rxjs/ajax: undefined
 * rxjs/fetch: undefined
 * rxjs/internal-compatibility: undefined
 * rxjs/operators: undefined
 * rxjs/testing: undefined
 * rxjs/webSocket: undefined
 * text-encoding: ^0.7.0 → 0.7.0 (already at latest)
 * ts-node: ^10.9.1 → 10.9.2
 * tslib: 2.4.1 → 2.7.0 (2.6.2, 1.14.1)
 * typescript: ~5.4.5 → 5.4.5 (already at latest)
 * typescript-example: ^0.1.7 → 0.1.7 (1.0.0)
 * webcrypto-shim:
 * xlsx: 0.18.5 → 0.18.5 (already at latest)
 * zone.js: ^0.14.5 → 0.14.10 (0.10.3)
npmGlobalPackages:
 * @angular/cli: 17.3.8
 * eslint: 8.55.0
 * source-map-explorer: 2.5.3


Describe the bug

I have an angular application that uses CUSTOM_AUTH flow for authentication,
This custom auth flow redirects the end user to a custom MFA page where the end users completes the challenge by entering an OTP.
If the OTP is correct I use the amplify rememberDevice method to track the device.

At this point in time if fetchAuthSession({force refresh: true }) is called it refreshes correctly.

The issue happens if the same user relogs in the tracked device , then we don't redirect them to the custom challenge flow , we directly log them in with the correct password.

Now this time the device meta data don't stay in the session storage ,

Now when the fetchAuthSession({force refresh: true }) fails with invalid refresh token error.
(Most likely because device key is not passed as payload in the refresh token api call.)

In v5 version of amplify we used to do something similar to
cognitoUser.getCachedDeviceKeyAndPassword()
Before calling the refresh token and it used to work .

Expected behavior

Refresh token call should work.
Amplify should handle the places where device meta data needs to be passed.

Reproduction steps

  1. Custom auth flow with device track
  2. Relogin on tracked device
  3. Call refresh token

Code Snippet

// Put your code below this line.

Log output

// Put your logs below this line


aws-exports.js

No response

Manual configuration

No response

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

No response

@github-actions github-actions bot added pending-triage Issue is pending triage pending-maintainer-response Issue is pending a response from the Amplify team. labels Jan 13, 2025
@cwomack cwomack self-assigned this Jan 13, 2025
@cwomack cwomack added the Auth Related to Auth components/category label Jan 13, 2025
@cwomack
Copy link
Member

cwomack commented Jan 13, 2025

Hello, @2-Dpot and thanks for creating this issue. Are you able to share more details about the custom auth flow that you've set up by sharing some of the frontend code where you're calling fetchAuthSession() and rememberDevice()? And can you give us more details on how you've set up your session storage and how the redirection step in your app is working? Thanks.

@github-actions github-actions bot removed the pending-maintainer-response Issue is pending a response from the Amplify team. label Jan 13, 2025
@cwomack cwomack added question General question pending-community-response Issue is pending a response from the author or community. and removed pending-triage Issue is pending triage labels Jan 13, 2025
@cwomack
Copy link
Member

cwomack commented Jan 13, 2025

Also, are you using the storing mechanism that Amplify uses out of the box (which would be localStorage), or is the deviceMetaData being stored in a custom rolled Session Storage?

@2-Dpot
Copy link
Author

2-Dpot commented Jan 14, 2025

Here is a small sample of my code , hopefully it explains the issue .

//app-config.ts
Import { sessionStorage } from "aws-amplify/utils";
Import { cognitoUserPoolsTokenProvider } from "aws-amplify/auth/cognito";
Import { Amplify } from "aws-amplify";

awsconfig = {
Auth: {
Cognito: {
userPoolClientId: ######
userPoolId:#####
}
}
}

Amplify.configure(awsconfig);

cognitoUserPoolsTokenProvider.setKeyValueStorage(sessionStorage);

//Login.ts
Import { signIn } from "aws-amplify/auth";

//If device key exist in cookie ? Do the below
let clientMetaData= {
DEVICE_KEY = ******
};
signIn({
username,
password,
options: {
clientMetaData,
authFlowType: "CUSTOM_WITH_SRP"
}
}).then(res => {
if(res.nextStep.signInStep === "CONFIRM_SIGN_IN_WITH_CUSTOM_CHALLENGE"){
// redirect to MFA page where we do the custom //challenge answer and remember device and //manually set device key on the cookie
// In this flow refresh token api works
}
if(res.nextStep.signInStep === "DONE"){
//Go to dashboard page directly , in this flow refresh token api fails
}

@github-actions github-actions bot added pending-maintainer-response Issue is pending a response from the Amplify team. and removed pending-community-response Issue is pending a response from the author or community. labels Jan 14, 2025
@2-Dpot
Copy link
Author

2-Dpot commented Jan 14, 2025

As you can see from the above code
cognitoUserPoolsTokenProvider.setKeyValueStorage(sessionStorage)
This is how I manage the storage in browser.

In MFA page when correct custom challenge is answered , I notice device details (deviceKey, dev ceGroupKey, randomPasswordKey)
are stored in session storage . Then I remember the device using await rememberDevice()

When Refresh token is called post this in the payload the deviceKey is passed by amplify and is successful.

But in the 'DONE' condition as seen in login.component.ts
When we call the refresh token method , no deviceKey is passed in the payload by amplify and it fails with "invalid refresh token" exception.

NOTE: All flows work completely fine if I'm using cookie as the default storage. As when we do that post logout , device details are not removed from the cookie , so in the next login refreshToken works completely fine as deviceKey is passed in its payload.
But I need to work with session storage where amplify fails to handle the device details.

@cwomack
Copy link
Member

cwomack commented Jan 14, 2025

@2-Dpot, thanks for the reply and additional context. If you're using sessionStorage and the user is logging out of the app like you described, then the expected behavior is to have the deviceMetadata wiped when the sessions ends (e.g. the user logs out). However, if you are looking to have the deviceMetadata persisted after this in the current state... you could use defaultStorage (which uses localStorage) or CookieStorage (more on that in docs here). But to be clear, this would also persist the auth tokens, which you may be trying to avoid.

You could potentially lower the TTL's for the auth tokens to the lowest value possible to try to help with all this as another consideration. Can you possibly clarify how you're using the device data a little more? Trying to see if there's a possibility that this is a feature request for more fine grained control of the the auth tokens/metadata based on the use case.

@cwomack cwomack added pending-community-response Issue is pending a response from the author or community. and removed pending-maintainer-response Issue is pending a response from the Amplify team. labels Jan 14, 2025
@2-Dpot
Copy link
Author

2-Dpot commented Jan 15, 2025

Giving more context inthe code which we use to handle device metadata.

//mfaPage.ts
confirmSignIn({ challengeResponse: 'xxxxx'}).then(res => {
If(res.nextStep.signInStep ==='DONE') {
fetchAuthSession().then(data =>
//Custom util service to just store device key in cookie
this.utilityservice.createCookie('DEVICE_KEY'+ username, data.tokens.accessToken.payload.device_key);
await rememberDevice();
)
}
})

//After some time calling refresh token like below
await fetchAuthSession({force refresh: true})

//The payload of the above cognito call has a refresh token and a deviceKey which I assume amplify takes care of by picking it from the session storage. But in my other flow the same refresh token api doesn't pass the deviceKey in the payload only refreshToken key exists as a result the call fails with invalid refresh token.
Is there away to make this work ?
For a 'tracked device' the refresh token cognito call needs to attach a deviceKey in the payload.

NOTE : I had to type all these from a phone due to a limitation so excuse my my spacing and code details.

@github-actions github-actions bot added pending-maintainer-response Issue is pending a response from the Amplify team. and removed pending-community-response Issue is pending a response from the author or community. labels Jan 15, 2025
@jjarvisp
Copy link
Member

Hi @2-Dpot, thanks for the additional information. I have a few more questions to try and help us get to the bottom of this.

  1. Could you try omitting the device key in the clientMetadata when you call signIn? Amplify should take care of this under the hood.
  2. Can you also provide some insight into how your custom auth triggers are setup? How are you determining a particular authentication attempt can bypass the MFA step? Perhaps some sample code would help here too.

Also, please keep in mind that when using session storage as the storage mechanism both device metadata and tokens will be lost when the tab is closed. Is this the intended behavior?

@github-actions github-actions bot removed the pending-maintainer-response Issue is pending a response from the Amplify team. label Jan 15, 2025
@cwomack cwomack added the pending-community-response Issue is pending a response from the author or community. label Jan 17, 2025
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 pending-community-response Issue is pending a response from the author or community. question General question
Projects
None yet
Development

No branches or pull requests

3 participants