angular-auth-oidc-client icon indicating copy to clipboard operation
angular-auth-oidc-client copied to clipboard

[Bug]: /token call with localStorage and multiple tabs does not work

Open scurk1415 opened this issue 2 years ago • 7 comments

Version

15.0.3

Please provide a link to a minimal reproduction of the bug

Can be reproduced on your own examples

Please provide the exception or error you saw

HttpRequest error with status 400:

Body:
error: "invalid_grant"
error_description: "PKCE verification failed"

Steps to reproduce the behavior

1. Set { provide: AbstractSecurityStorage, useClass: DefaultLocalStorageService } (or your own version of LocalStorage storage)
2. Open 1 browser tab (when not authenticated)
3. Open another browser tab (when not authenticated)
4. Go to the first tab and login
5. You get redirected to the unauthorizedRoute (with /token endpoint throwing an error)

A clear and concise description of what you expected to happen.

I expect to be redirected to the redirectUrl and the application to work

Additional context

This flow seems to be working with the default sessionStorage. It works if we login on the 2nd tab (specified in the steps to reproduce), but not if we login on the 1st tab. I guess it has something to do with the nonce or code_challenge parameters that get appended to the url when we get refirected to the login page (we use Keycloak, but i guess that it is not that important).

We also use your AutoLoginAllRoutesGuard which indefinitely triggers the /token endpoint and blocks all processes (but i guess this can also be caused by our routing, so you can probably ignore this part).

scurk1415 avatar Mar 14 '23 14:03 scurk1415

Yes localstorage is shared across tabs. So if you open multiple tabs, all use the same localstorage. It would be more safe to use session storage. We do you not use this?

Greetings Damien

damienbod avatar Apr 16 '23 15:04 damienbod

The customer wants to be logged out from all sessions when they logout on one tab. With sessionStorage they get logged out just in one tab. With localStorage they get logged out from all, but then logging in becomes a problem (as described in the issue).

I think you can probably reuse the parameters (nonce/code_challenge) for certain scenarios but i guess you would need a new config for that or the AbstractSecurityStorage would need another method so that you know when to reuse.

scurk1415 avatar Apr 16 '23 17:04 scurk1415

Sounds reasonable, the client should know that the overall security is worse by using local storage and and global client logout compared with session storage. The logout is supported, but you shared sensitive date for all js scripts running.

You could implement a custom storage, but I don't think we could separate the security bits, these are not made public I think...

Greetings Damien

damienbod avatar Apr 16 '23 17:04 damienbod

@damienbod

You could enforce the codeVerifier to be stored in sessionStorage instead of using the provided implementation of AbstractSecurityStorage.

vds-simon-lapointe avatar May 30 '23 13:05 vds-simon-lapointe

You can use sessionStorage for tokens etc and use localStorage to logout all of the logged-in tabs like this:

    window.addEventListener("storage", (event) => {
       if (localStorage.getItem(event.key || "") === REMOTE_LOGOUT_REQUEST) {
          this.logout();
       }
    });

fritzwf avatar Aug 17 '23 21:08 fritzwf

@fritzwf would you also need to add the below in the function where the logout button has been clicked?

localStorage.setItem('logout', 'remote-logout');

gmiked avatar Aug 29 '23 15:08 gmiked

@fritzwf would you also need to add the below in the function where the logout button has been clicked?

localStorage.setItem('logout', 'remote-logout');

Yes, you would either use the this.logoff() function itself, or you could instead send an event using rxjs. That event would go to were ever the logoff() function is located and it would call the logoff() function.

Also, when the next login starts, remove the logout from the localStorage, that will have it ready for the next login. Also, when the logout is called, you set the localStorage: localStorage.setItem(LOGOUT_REQUEST_KEY, REMOTE_LOGOUT_REQUEST), that will trigger the localStorage event so every tab will get the event and logoff.

fritzwf avatar Aug 29 '23 18:08 fritzwf