Trying the new Refresh Token Rotation in a React SPA. Are 3rd party cookies supposed to be required?

Nice to see Refresh Token Rotation shipped today, congrats Auth0 team!

So I’m trying to test it out using @auth0/auth0-spa-js v1.7.0 on a minimal React SPA (deploy, repo) carefully following what I think should be the relevant quickstart from the docs. I used create-react-app + TypeScript and things are pretty vanilla, here’s the refresh token opt-in

OK, so here’s the GIF of what’s going on:

TL, DR: 3rd party cookies appear to be required for ‘silent auth’ aka the refresh button. Is that right? I thought one of the main selling points of refresh token rotation was to avoid needing to enable 3rd party cookies, given the browser vendors are pushing that hard these days. But maybe I’ve missed something/some new config perhaps.
Could anyone help me understand please?

@randynasson @steve.hobbs thanks for your efforts on shipping this!

Hi @onpaws,

Thanks for trying out the new feature! In that default configuration with refresh tokens turned on, you will be storing the refresh token in memory. So when you come to the app fresh or refresh the page, you won’t have a refresh token.

In any event that you don’t have a refresh token, the SDK falls back to the legacy iframe method to try and get you an access token and a refresh token based on your existing session. This unfortunately has all the pitfalls of requiring 3rd-party cookies to work, so if they are blocked, getting a new refresh token won’t work in this case.

We added another new feature to this SDK to get around this somewhat, which is an opt-in to storing tokens in local storage. This can be configured by setting cacheLocation to localstorage, which means the tokens can be persisted across page refreshes.

Give that a try and let me know how you get on. I will make sure this detail is covered properly in the readme :+1:

Hi @steve.hobbs,
Brilliant, thanks for the quick response.

I went ahead and tried it and the refresh is now working with 3rd party cookies disabled, as you said, thanks! One-liner lives here in case anyone else reading this is interested.

Have a question about local storage, I realize this situation in general is a complex issue with multiple tradeoffs and I’m probably ignorant on the reasoning here. What I’m hoping to understand: why local storage vs a cookie?

Based on implementing a JWT-based auth system last year I was under the impression it was considered desirable from an XSS risk mitigation perspective to use cookies with the HttpOnly flag set. So on that project we set the refresh_token as a cookie with the usual security flags and a path, and then the server subsequently returns ephemeral access_tokens that live in browser memory only. Obviously the spec reflects a lot of smart people’s efforts, and my above solution was built before that spec was finalized, so I may be ignorant of a problem with the above approach.

I do realize refresh token rotation means rotating refresh tokens frequently :slight_smile: and I’m guessing there are reasons the token has to live local storage, but I’m curious to understand why. What about this system precludes using cookie(s)? If I understand right, on SPA page init we’re making a request to the Auth0 endpoint anyway. Seems like the endpoint could ostensibly respond to a cookie-presented token then, no?

Are there plans in the works to support cookies in the future? Or is this whole idea fundamentally Not A Thing.

Thanks again, appreciate your insight!

@onpaws One big reason is that one of the reasons we introduced this feature is because cookies are being blocked by enhancements in browser privacy technology, such as Safari’s ITP or by default in Brave.

Strictly on the client side, we assume that this SDK is being used with a SPA architecture, meaning you probably won’t have a backend to set cookies. If you did, you would most likely be doing authentication on your backend and wouldn’t be using this library. In any case, the cookie in this scenario could not be HttpOnly as it would have to be read by JavaScript.

In the end, whether you store tokens in a cookie or in local storage doesn’t make too much difference as they both suffer from the same issues regarding XSS vulnerabilities and so on.

I do realize refresh token rotation means rotating refresh tokens frequently

You’re correct, but they also have built-in reuse detection - if a refresh token is leaked and used, a subsequent exchange will kick in the detection and the entire “family” of refresh tokens will be invalidated.

1 Like

Hi @steve.hobbs reading through this thread and I think I have a good grasp on the implementation. So as I understand, storing tokens or other sensitive data in localStorage is generally a bad practice as it makes your application vulnerable to XSS. I have a few questions I was hoping you could help with that are related to this post but if need be, I can create a separate thread.

  1. With the Rotating Refresh token approach, it’s okay to store the refresh and access tokens in local storage as the Auth0 team has built in the reuse detection feature, correct?
  2. When the reuse detection is alarmed and all the refresh tokens are invalidated, will this just essentially render the session deactive for the legitimate client and thus require them to login?
  3. I have a backend Node/Express API which my React SPA uses to get non-user related data. When user logs in on client and get the refresh, access, and id token, I’m thinking that I store the refresh token in local storage on client while relying on refresh token rotation to render that token useless if need be and providing the user with a secure session through page refreshes. When I need to make an auth call to get user-related data, should I make the call that gets a new access and refresh token directly from client-side or should I make a call to my Express API first which then makes the call to Auth0 to get new tokens? I would think the former would work but wasn’t sure if there were vulnerabilities I could encounter doing it that way.

Apologies for the block of questions. Any help will be greatly appreciated!