okta / okta-auth-js

The official js wrapper around Okta's auth API
Other
447 stars 261 forks source link

Web workers for token renew and expiry #1474

Open erichey620 opened 10 months ago

erichey620 commented 10 months ago

Modern browsers will throttle timers if a window is minimized (among other conditions) - You can start to see throttling after about 5 minutes. See: https://developer.chrome.com/blog/timer-throttling-in-chrome-88/

I am getting issues reported where a user’s accessToken does not get refreshed automatically when the window is minimized. User maximizes browser and continues to work, but the token has expired and the app is stuck in a failed state. 404’s for all network calls and can’t recover.

There was a previous issue reported , Originally posted by @jaredperreault-okta in https://github.com/okta/okta-auth-js/issues/1445#issuecomment-1673576831_

But it seems the “solution” for the person reporting it was to just sign the user out due to inactivity. I don’t think that will suffice if Chome could start causing issues only after 5 minutes. Web workers likely need to be introduced to reliably track token expiration times and fire the events to ensure a seamless interaction.

jaredperreault-okta commented 10 months ago

@erichey620 Are you using refresh tokens? The solution proposed in #1445 isn't necessarily suggesting to sign the user out (a user isn't technically "signed out" until the refresh token is also expired or revoked). The suggestion is to allow the access token to expire when the tab is inactive and once the user re-visits the page, the access token will be checked, found to be expired and ultimately renewed (via the refresh token). This won't require any user input/interaction

Do you mind elaborating a bit more on your use case? My bosses love user stories :)

erichey620 commented 10 months ago

Hey, thanks for the reply! Follow-up question on your suggestion: “once the user re-visits the page, the access token will be checked, found to be expired and ultimately renewed (via the refresh token). This won't require any user input/interaction” Is that something already out-of-the box with how the Sdk works or would that need to be written in the app/consumer code? For instance right now once the browser “wakes up” the sdk autoRenew doesn’t catch that the access token is expired, so it won’t get refreshed (granted I’m not using refresh tokens). Which is why I manually added a web worker to my app, to call the ‘refreshTokens’ endpoint about ~30 secs before expiration. Rather that using autoRenew.

At the moment I dont use refresh token - when I tinkered around and requested one, it had the same expiration as the accessToken. So I’d likely need to work with our crew to get that refresh token last longer than the access. Although in my Implementaion with webWorkers not sure if the refresh token would buy me anything. But moving to the proposed solution it would be… just need to flesh out the “renew access token after it expires” and what “triggers” that exactly (if not going with a web worker direction) (and also assuming the Sdk doesn’t do that for me).

Maybe an interceptor for any Http calls that will check the validity of the access token (or if it got autoRemoved) and refresh if needed? - that maybe what you had in mind? I currently have an interceptor to add the access token as the bearer but it assumes it’s a valid one.

overall I think it would be a nice improvement if the Sdk could use a worker to keep track of the accessToken expiration and renew it on time even with minimized tabs, to reduce any client/consumer implementations for renewing or other bad side effects. Let me know your thoughts!

erichey620 commented 10 months ago

Also a current downside of my home-grown web worker solution is that with multiple tabs open, they’ll all fire off a request to renew the tokens.. whereas the autoRenew I think was smart enough to only have one master tab do so.. not sure how that gets tracked exactly in your Sdk code, or if that’s something accessible somehow if I wanted to mimic that behavior

jaredperreault-okta commented 10 months ago

Is that something already out-of-the box with how the Sdk works or would that need to be written in the app/consumer code?

Assuming you're using refresh token, yes, this is out-of-the-box functionality. You will need to set tokenManager.autoRemove to false as mentioned in #1445

new OktaAuth({
  ..., // current config
  tokenManager: {
    autoRemove: false
  }
});

For instance right now once the browser “wakes up” the sdk autoRenew doesn’t catch that the access token is expired, so it won’t get refreshed (granted I’m not using refresh tokens)

Do you happen to know if you token is actually expired?

At the moment I dont use refresh token - when I tinkered around and requested one, it had the same expiration as the accessToken. So I’d likely need to work with our crew to get that refresh token last longer than the access. Although in my Implementaion with webWorkers not sure if the refresh token would buy me anything.

Yes, you can configure refresh tokens to last longer than access tokens via the Okta Admin Console. This would eliminate the need for worker-based timers, as the refresh token can be used to renew the now expired access token independent of the user's Okta session (I am extrapolating you're current renew mechanism is based on the Okta session)

But moving to the proposed solution it would be… just need to flesh out the “renew access token after it expires” and what “triggers” that exactly (if not going with a web worker direction) (and also assuming the Sdk doesn’t do that for me).

authjs should automatically renew your tokens with the following configuration

new OktaAuth({
  ..., // current config
  tokenManager: {
    autoRemove: false
  }
});

Maybe an interceptor for any Http calls that will check the validity of the access token (or if it got autoRemoved) and refresh if needed? - that maybe what you had in mind? I currently have an interceptor to add the access token as the bearer but it assumes it’s a valid one.

It's probably a good idea to check if a token has expired before using it