Reputation: 283
When using the OAuth 2.0 JWT Refresh token implementation I came across the issue that it's really difficult to implement a solid Refresh Strategy on the Web Browser Client Side. Multiple Tabs can lead to a racing condition with the requests.
The RFC does not explicitly mention to have the Refresh Token on the Server side only valid for one (the first) request, but I figured it was a good idea to invalidate the Refresh tokens when they are used.
There are already multiple "solutions" on stack overflow but none of them seem to be straight forward.
One solution is to add Jitter to the requests and synchronize requests over the Local storage.
If I understand correctly you would put a variable into the Local storage when the request is started other tabs check if this variable is set and then don't start the refresh? Do you know an example implementation of this? Maybe in React?
Upvotes: 15
Views: 7555
Reputation: 61
Take a look at Navigator.locks
, which can be used to get a lock across different contexts, and then perform a request when you acquire it:
https://developer.mozilla.org/en-US/docs/Web/API/Navigator/locks
Then the code could look as follows:
window.navigator.locks.request(
'unique_name_for_refresh_checking',
async () => {
if (needRefresh) {
performRefresh()
}
},
)
This will make only the tab that has acquired the lock actually perform the refresh request.
You do have to make sure that the response from this request is propagated to other tabs by some method. For example: writing to local storage with the new tokens and listening for this in other tabs.
Upvotes: 2
Reputation: 875
I made a solution for our internal project several months ago and saved the business-insensitive version as https://github.com/hey-web/share-token-among-tags.
The core approach of it as follows:
Hope this would help.
Upvotes: 2
Reputation: 673
I use the page Visibility API https://developer.mozilla.org/en-US/docs/Web/API/Page_Visibility_API for this purpose. When tab is inactive I cancel renewal subscription and setup for renewal when tab is active again.
My code for Angular is:
constructor(
private router: Router,
private http: HttpClient,
private tokenService: TokenService,
@Inject(DOCUMENT) private readonly documentRef: Document,
) {
this.getToken(); // From local Browser store
this.loggedIn = this.isAuthenticated();
this.status = new BehaviorSubject<boolean>(this.loggedIn);
this.documentRef.addEventListener("visibilitychange", () => {
console.log(document.hidden, document.visibilityState);
if (document.hidden) {
this.cancelRenewal();
} else {
this.getToken();
this.loggedIn = this.isAuthenticated();
this.status.next(this.loggedIn);
this.scheduleRenewal();
}
}, false);
}
Upvotes: 1
Reputation: 29263
If you are using a cookieless SPA the most common solution is to avoid refresh tokens and do this:
COOKIELESS SPA RESOURCES
Here is some stuff of mine that may help, if I'm understanding your setup:
Upvotes: 3
Reputation: 31
The answer above does not really answer the question:
Using the OIDC client library does not solve this problem, in fact it does not even use refresh tokens as far as I know.
Storing tokens in memory or session storage does not solve the problem but will generate even more, see below.
Using the AS's session cookie is not feasable in some cases. Usually this is a cross-domain cookie which cannot be used reliably on other sites. This concept is called "silent renewal" and requires the use of a cross-domain cookie in an iframe to refresh tokens (using the AS session). This concept sounds nice, but with browsers and users blocking more and more cross-domain tracking mechanisms this is really dangerous to use: in most cases, blocked cookies cannot be detected (which leads to sudden logouts after some seconds, especially when using the OIDC Session Management mechanisms. Redirecting through the AS when refreshing tokens is also not an option, as in many cases, tokens are JWT and only valid for some minutes, and breaking the experience by redirecting away from the app every few minutes is not an option.
With PKCE and Authorization Code flow in the browser it is fine to use and store refresh tokens, but as the original poster said, care has to be taken when refreshing (especially when refresh tokens can only be used once, which is desired in browser environments!)...
Upvotes: 3