aws-amplify / amplify-js

A declarative JavaScript library for application development using cloud services.
https://docs.amplify.aws/lib/q/platform/js
Apache License 2.0
9.43k stars 2.13k forks source link

Store User in sessionStorage #2552

Closed cocacrave closed 5 years ago

cocacrave commented 5 years ago

If I understand correctly, Auth.signIn stores User in localStorage then wrapping with Authenticator sets the user back into authState and authData states on componentDidMount with a Auth.currentAuthenticatedUser call. So persisting user state between sessions works out of the box but what if the user doesn't want to store information on that particular device?

Maybe add option to Auth.signIn with a remember me feature to store User in either localStorage or sessionStorage could work?

Possible workaround for now is to listen to window.unload event to fire Auth.signOut but as far as I know there is no way to detect between tab/browser close vs page moves. And what if Auth.signOut fails?

Thanks

powerful23 commented 5 years ago

@cocacrave you can switch to different storage by using this: https://aws-amplify.github.io/docs/js/authentication#managing-security-tokens

cocacrave commented 5 years ago

@powerful23 Awesome! Thanks you.

cocacrave commented 5 years ago

Sorry for reopening. Not exactly sure if I did this right. I'm configuring Auth.configure({ storage: rememberMe ? localStorage : sessionStorage }) where rememberMe is an option on the login form.

This stores user in either session storage or local storage where before only local storage. So now the problem is when I move url and back the Auth.currentAuthenticatedUser() returns not-authenticated. But the sessionStorage still holds the user values like accessToken, clockDrift, idToken, refreshToken, LastAuthUser.

Maybe the problem is that I set storage to session but with page moves, the storage is set to default (local)?

How do I get user object from those values set in sessionStorage?

powerful23 commented 5 years ago

@cocacrave are you still having this issue? You can check the rememberMe value when page moves to see which storage is passed into the module.

cocacrave commented 5 years ago

I suspected the reason was in Authenticator from aws-amplify-react looks up localStorage as default to set the user back into state during componentDidMount with checkUser(). I'm sure this will bite me later but I ended up rolling my own Authenticator with my own checkUser() checking sessionStorage.length && Auth.configure({ storage: sessionStorage }).

I hope it doesn't come back and haunt me later :) Thanks for checking up on the issue.

MattM31 commented 4 years ago

This is probably completely wrong but I've just done this and it seems to work. In Amplify.configure I've set it as 'storage: sessionStorage,' this makes it store it is localStorage and sessionStorage though. Then in my App function, I've added localStorage.clear(); this wipes local storage. It stays logged in when you refresh but logs the user out when you close the browser or tab. Is this a really bad way to do it?

karlvonbonin commented 4 years ago

Thanks for the help guys - I have exact the same issue and that helped me out! (@MattM31 )

When you do 'storage: sessionStorage,' in the config - it only does store it into the sessionStorage not in the Local anymore. There you can build up your switch betweeen local or session.

Update: Retrieving the current user from Storage: DONT MAKE THE MISTAKE TO DO 'storage: sessionStorage,' in the (Global)config on load. Because Auth.currentAuthenticatedUser will lookup only in the session of the global config.

Leave it empty in the global config and " Auth.currentAuthenticatedUser" will look in both storages. You can save the Data in Local or Session if you specify the config righ before the login.

Here is my example:

rememberLogin
      ? Auth.configure({ storage: localStorage })
      : Auth.configure({ storage: sessionStorage });

    try {
      const awsUser = await Auth.signIn(username, password);
;
      console.log({ awsUser });
    } catch (error) {
      console.log("error signing up:", error);
    }
  };

Hope that helps!

tiomno commented 4 years ago

Nothing to do with the issue here. 😅

This is just to point out the security issues of using localStorage for sensitive data. You should use server-side storage for sessions and the like. As @powerful23 mentioned here https://github.com/aws-amplify/amplify-js/issues/2552#issuecomment-454877997 you could go and check https://aws-amplify.github.io/docs/js/authentication#managing-security-tokens

Please check these out for proper explanations: https://dev.to/rdegges/please-stop-using-local-storage-1i04 <— Please Stop Using Local Storage https://cheatsheetseries.owasp.org/cheatsheets/HTML5_Security_Cheat_Sheet.html#local-storage <— OWASP recommends not using Local Storage for sensitive data.

Happy coding! 🙂

hyungjunk commented 4 years ago

@Alphavader

It seems cognito only looks at localStorage to retrieve token for me. If I refresh the page, it asks me to login again if token is saved at sessionStorage. I left the global config as-is like you suggested.

When I change my global config to Auth:{storage: window.sessionStorage} after saving the token to sessionStorage, it works.

What am I missing here?

jarrvis commented 3 years ago

@hyungjunk

Same here. But I doubt that auth module can do it automatically (check also session storage). I think it would be weird if it worked since there might be a lot of Storage implementations in runtime. It would be a high expectation for amplify to require to check all those places.

spdrman commented 2 years ago

I had encountered this same problem. I feel this should be far better documented at the amplify docs site...

The source of the problem for me was two fold:

  1. I was initializing my Auth.config in index.tsx instead of inside the App function; and,
  2. I was including the storage: window.sessionStorage inside my awsConfig object, that I was passing to the Auth.configure() call.

Keep in mind that Auth.configure, when called, will check both sessionStorage and localStorage, unless you specify one or the other inside the awsConfig object that you passed to Auth.configure(). It will then grab the token and auth the user automatically on loading the App component in react.

This was the solution for me too:

rememberLogin
     ? Auth.configure({ storage: localStorage })
     : Auth.configure({ storage: sessionStorage });
...

I basically created a n awsConfig object that is exported, and gets initialized at the top of App.tsx (inside the App function). I made sure the awsConfig object doesn't have the storage: ... parameter.

Then, in my Login component, I have a control flow to test whether the user selected "remember me" or not. If they did then it calls Auth.config with the same parameter passed to it of awsConfig, but also the added storage parameter set to one of two options, depending of if we want to remember user or not (relevant code only):

...

rememberLogin
     ? Auth.configure({ ...awsConfig, storage: localStorage })
     : Auth.configure({ ...awsConfig, storage: sessionStorage });

...

try {
     const awsUser = await Auth.signIn(username, password);

...
eduardocmoreno commented 2 years ago

I'm using Vue 3, and I have no clue why leaving the storage prop empty on my init config didn't work. What that worked for me was:

//index.js
Amplify.configure({
  storage: !!sessionStorage.length ? sessionStorage : localStorage
});

//SignIn.vue
const currentAuthConfig = Auth.configure();
const rememberMe = ref(false);

function submitHandler() {
  Auth.configure({
    ...currentAuthConfig,
    storage: rememberMe.value ? localStorage : sessionStorage
  });

  //userStore.signIn(...);
}

Lmk if that works for you guys, or if that is a bad approach.

github-actions[bot] commented 1 year ago

This issue has been automatically locked since there hasn't been any recent activity after it was closed. Please open a new issue for related bugs.

Looking for a help forum? We recommend joining the Amplify Community Discord server amplify-help forum.