Thanks for responding so quickly and sending it over to the product team!
In this use case, all of the micro apps (similar to the micro services concept) are SPAs using username-password authentication. There’s no IdP to worry about. We also use a custom login form instead of the Auth0 Lock widget.
How it Works
Per your question, the prototype I’ve created is pretty simple; although, I’m about to rearchitect it so the iframe app handles Auth0’s checkSession
and not each parent micro app, but this is the original working design:
- Have the iframe loaded in HTML when the page renders.
- The iframe will setup an interval that checks
localStorage
for the current authentication state (true
orfalse
) - Create a message listener in the parent app and specify the correct origin.
- Send a message to the iframe asking for the current authentication state. This also sets up
event.source.postMessage
in the iframe and allows it to send authentication updates.
At this point, nothing’s changing. As soon as you login, this is what happens:
- Send
isAuthenticated: true
over to the iframe. - The iframe receives a state change message and immediately writes it to
localStorage
. - On each interval, the iframe in each tab is checking for state changes. Because the state changed, a message is sent back to the parent app in each tab with the new authentication state, and they can react accordingly.
If you logout in one tab, it’s the same thing, but you send isAuthenticated: false
instead.
This implementation can be expanded to sync timers between tabs for lastUserActionTime
if you have a logout timer and want to keep it in sync between tabs. This way you don’t logout users in one tab because they were active in another tab.
I also agree this would be perfect for a Service Worker! Since they require a valid SSL cert (not even self-signed), they’re extremely difficult to use locally especially with a large team. The iframe method is much simpler if not significantly slower in terms of load times . I haven’t figure out a good solution for this problem, but if Auth0 eventually creates this solution, I won’t have to worry about it in the long term.
Other Notes
I was originally under the impression a small token lifetime was 5-10 seconds, and I used that range for testing my synchronization code originally. After reading the Auth0 docs again, I raised the token lifetime and instead, posted this question. It makes sense to use checkSession
when the session expires, just not when synchronizing authentications.
After reading through more docs, I noticed checkSession
does silent authentication, but also only tells me if you’re session is expired, not if you’ve logged out. I could check for login_required
on the error object, but I’m not certain that solves the other issues I’m having:
- Checking your session every 5-10 seconds or less is not the intended use case.
- It does a silent authentication and give me a new token each time. This extra functionality isn’t required for synchronization, only token refresh.
- I have no way of knowing if the session was logged out already or if it just expired. Only one browser tab should handle token expiry by calling Auth0’s logout function. Other tabs should simply redirect back to the login portal and provide a method of instantly redirecting back when any one of the tabs logs back in.
I was starting to wonder if it’s really important to keep these tabs in sync within 1-10 seconds of each other and came to the conclusion yes, this is still important.
From my perspective, it’s a terrible user experience to be logged into our system of apps and be logged out in one tab, but not in another. When one tab’s logged out but another is still logged in, all-of-a-sudden you might receive a bunch of 401s or stop receiving messages over WebSockets. A user won’t realize what’s going on. If the apps all instantly log you out at the same time, you don’t even need to handle the case where you’re getting multiple 401s in your app as they’ll be non-existent.
It’s possible I’m completely misunderstanding how this works though. It could even be that as soon as a 401 comes in, I’m supposed to do a checkSession
and figure out a way to handle it from there. I really don’t know.
I looked into the getSSOData()
function, and it looks like checkSession()
is the recommended method; although, I could use getSSOData
to specifically check only the sso
property for true
or false
like I’m doing now with my iframe solution. Is this method meant to be called ever 1-10 seconds from various browser tabs on the same client?