Auth0 provide extensive list of resources describing best practices for the authentication. Among them there\'s a constant stream of advice not to use localStorage
Although I don't know much about Auth0 implementations, features and design decisions, from my general understanding of OAuth2 and security, I can try connecting the dots.
A single recommendation by itself doesn't provide enough security or desired functionality, but when used with a combination of other related recommendations, we can achieve the desired level of security and behavior.
Let's go through the points you raised.
From my perspective accessing the tokens itself doesn't extend the scope of attack. If the attacker has control over the victim's browser they can execute the calls, using the token, from the affected browser itself
The problem with localstorage
is:
localStorage
and sessionStorage
are not shared across sub-domains. This is show stopper for SSO functionality (There are some solutions using iframe
, but those look more like workarounds rather than a good solution. And when the response header X-Frame-Options is used to avoid clickjacking attacks with iframe
, any solution with iframe
is out of question)
XSS can send the access and/or refresh tokens to remote servers controlled by the attacker and thus allowing the attacker to impersonate the user
Note: The vulnerability mentioned in point 2 can be mitigated by using a Sender Constrained Access Tokens approach where the client has to prove that they indeed own the token. Another alternative is the fingerprint approach mentioned in OWASP which needs a cookie. However, it seems Auth0 doesn't implement any of these. Therefore, the recommendation of avoiding localstorage
makes sense.
Auth0 recommends using auth0.getTokenSilently() from their SDK to obtain the token, but as far as I see, there shouldn't be any reason why attacker couldn't call this method themselves
Correct. That's why
getTokenSilently()
method requires you to have Allow Skipping User Consent
enabled in your API Settings in the Dashboard. Although I don't see a specific guideline on this, but I think if you store the token in cookies you don't need this option to be enabled and thereby eliminating any possibility of misuse of the method.The only way that I know where XSS wouldn't be able to access the tokens is basically using httpOnly cookies, but that creates new vectors by itself (CSRF) and still wouldn't prevent attackers from calling the api from within the affected browser
True. But you can mitigate this with one or a combination of the following approaches:
SameSite
cookie. Refer the doc here. If the browser doesn't support SameSite
cookie, follow another approach from belowStrict-Transport-Security: max-age=<expire-time>; includeSubDomains
to allow only secured connections to prevent any man-in-the-middle overwrite the CSRF cookies from a sub-domain