-
-
Notifications
You must be signed in to change notification settings - Fork 1.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Forcibly reload app from server when API is redirected #3286
Conversation
✅ Deploy Preview for actualbudget ready!
To edit notification comments on pull requests, go to your Netlify site configuration. |
Bundle Stats — desktop-clientHey there, this message comes from a GitHub action that helps you and reviewers to understand how these changes affect the size of this project's bundle. As this PR is updated, I'll keep you updated on how the bundle size is impacted. Total
Changeset
View detailed bundle breakdownAdded No assets were added Removed No assets were removed Bigger
Smaller No assets were smaller Unchanged
|
Bundle Stats — loot-coreHey there, this message comes from a GitHub action that helps you and reviewers to understand how these changes affect the size of this project's bundle. As this PR is updated, I'll keep you updated on how the bundle size is impacted. Total
Changeset
View detailed bundle breakdownAdded No assets were added Removed No assets were removed Bigger
Smaller No assets were smaller Unchanged No assets were unchanged |
I found this because I have the same issue with Authelia and Actual. |
Could we do something like this? I run silverbullet as well and it seems like they were able to solve the issue by just setting |
Reloading when an API query gets a 302 would work for my setup (and I'd guess many other people's), however there are probably many valid setups where a 302 is normal and the correct action is to have the API follow the redirect and return the redirected response normally. Can we be confident that any time a 302 is returned that we need to reload? Maybe a configuration setting which has this automatic reloading as an optional feature? |
Maybe an option where you can configure hosts that if we get redirected to one of those hosts we reload? In this case any time I get a redirect to auth.mydomain.com I want to reload |
I don't see why any config would be necessary. If you make a request to a trusted destination and the request is calling for you to be redirected, you should redirect. You don't even need to handle reloading I think. As long as your proxy sends a redirect call, it should just directly redirect you without prompting. That's how normal webpages without service workers would react anyways. |
Just glacing over the source I see this which appears to let you wrap the fetch command. Line 32 in 9c0e6a3
|
A whitelist would also be an option but as this is a common problem with reverse proxies + auth, I think having to first figure out what's wrong and then find the solution would be a bit annoying to users. As I see it, there are two common behaviors that can happen when you get a 302:
Another point to consider is that some auth solutions pass the return URL to the auth page. |
I'm happy to implement doing this automatically when an API request gets a 302 if maintainers agree that is appropriate. My initial design was erring on the side of not breaking existing setups.
The problem is only api requests get redirected. GET requests for the page itself get served by the service worker with cached code and therefore do not get redirected.
I agree, we do not want to follow the 302 that originates from the API request because after authentication finishes we'd be redirected back to the api call; not the app. Instead we'd want to force a uncached GET the current page and follow the resulting redirect.
The way I've figured out how to do that is by unregistering the navigation service worker and reloading. This is what I do in my |
I think the approach needed here would be to change the service worker logic to stale-while-revalidate, which causes it to still fetch in the background if there is a connection. That way we can handle the background fetch and redirect if it returns 302. I'm on board with just redirecting unconditionally for now; if someone does start using a setup where the redirect isn't an auth request, we can help them at that time. Another thing worth noting is that IIRC one of the first things the app does when it loads is make an API request to check if the server has been initialized. Assuming my memory is correct, maybe handling only API requests is fine? |
In this case, nothing happens since the redirect url cannot be determined.
It's probably better to use network first. Stale while revalidate would work but only on the second request since it pulls from the cache first. |
Looking at the config, it seems like no runtime caching is being performed right now. Presumably, all you would need to do is handle the redirect that the service worker returns. A slight disadvantage is the return url would likely be an API call. I suppose if you unregister the service worker and remake the request, that will direct the user to the right place. I'm just not sure of the implications of unregistering the service worker. https://github.com/actualbudget/actual/blob/master/packages/desktop-client/vite.config.mts#L155 |
I've added functionality to automatically reload when an API call gets redirected. Please let me know if there's anything to improve |
Is the reload button on settings even needed still? Can that be removed? |
I agree this would likely be quite a rare scenario, but not impossible. Do you (or anyone else!) have any thoughts on mitigating cases like this? What's the risk appetite for potential issues like this? Maybe it's best to wait to see if anyone actually has this issue before we try to fix it? |
One option we've used in the past is an experimental feature that defaults to on. That way, if folks run into any problems, they can turn off the redirects, disable the feature, and then report the issue. |
That doesn't seem like a bug worth fixing. Say a user encounters an infinite reload. They disable the automatic reload feature (which they're unlikely to disable without clearing browser cache because now the page is reloading constantly). Would we expect the server to function at all in this case? The user would still continue to experience redirects when attempting to reach the API. I think if someone did have this issue, having it loop like this would show them that something is wrong with the configuration. |
I agree its probably not worth worrying about an edge case that is unlikely to happen, especially since this will help a bunch of people as is. The issue of needing to reauthenticate trips people up all the time. |
Alright, I'm fine to address it later if someone runs into it 👍 |
This doesn't seem to be working for me anymore on edge. I wonder if something broke this. |
Same, I'm on 24.10.1 and it does not reload even though all the API requests are redirected to my auth page. |
I realize we can change the service worker to not capture the sync API call to avoid this issue entirely. |
I am on 24.11.0 and am still experiencing a sync issue when going through Authentik after the auth token expires. |
I recently installed Actual 24.11.0 and this is also not working for me. |
To clarify, the issue presents itself independently from the Authentik expiry. I have set it to 52 weeks last time I had the issue and had to delete all browser data to force a reload and had again the issue today, a week later. A fix would be greatly appreciated as this makes Actual difficult to transition to in a family setting. I intend to get my wife to move off YNAB in favor of Actual and certainly don’t see her clearing her browser data on a frequent basis. |
What browser are you using? What errors are you seeing? What do the redirects look like?
keep in mind session expiry and token expiry are distinct. Your token may have expired, but it may still need to redirect to your auth to get a refreshed token using your session which has not yet expired. |
I am using Firefox normally on Desktop but have the same issue with Chrome and also on Mobile (Samsung Internet, Chrome, Firefox). When the issue happen, the sync would stop working, I would see the server as offline. If I close the file and delete it, I cannot see the server at all, it would say that actual-fqdn.com cannot be reached, please check SSL configuration. I will check my redirections next time the problem occurs. I was not aware of the differences between session expiry and token expiry, thanks for pointing it out. Considering those two parameters, I don’t see how the Actual token would expire before the session itself expires. So I am not clear on what exactly is happening. |
I have the issue currently with my phone. Going to actual-fdqn.com, it simply loads the offline file showing the server offline. Once logged in Authentik, if I try to reload actual-fdqn.com or open a new tab in the same browser exhibiting the issue, it loads immediately the offline file, with the server shown offline... Is there a better way to force a redirection to Authentik? So far the only I found to get around the issue in any browser is to clear all data which gets old every time. When the issue occurs, the browser does not even attempt to reach Authentik, the offline file is loaded. It is clear as day, as I can unmap the actual-fdqn.com in Nginx proxy manager and it would still resolve loading the offline file.... |
Ah interesting. Ultimately the request fails because it is blocked by CORS. I doubt the current check is detecting this as a redirected request and instead only seeing a CORs error. |
There's a couple of fixes here
|
Telling people to set the necessary CORS headers seems like a sufficient solution, but perhaps the docs should be updated to indicate that this might be necessary? |
The cors headers was definitely the fix! I think we should just notify people about this in the documentation. I'm running nginx ingress with authentik and this config did it for me. Working flawlessly now.
|
Thanks, it took me a while to figure out how to adapt it in Nginx proxy manager, but I got it working eventually. As a note for those in the same case: edit the authentik proxy in NPM, create a custom location for /, click the cog wheel and paste the code from alexyao2015 from "set $allowed_origin"";. |
This adds a wrapper around fetch so the application is reloaded when an API request is redirected. The motivation for this is as a workaround for the bug in #2793.
This issue occurs when using forward authentication with something like authentik with a proxy (e.g. caddy, traefik). The proxy checks with the auth service whether all requests to the host are valid, if they are they are forwarded onto the backend server (in this case actual server). If the request is invalid e.g. the cookie has expired or the user has not authenticated yet, then the proxy redirects the user to the authentication page. After authenticating they are redirected back to what they were originally requesting.
For a more standard application; after a authenticatoin cookie has expired the next time the page is reloaded it would redirect to the auth page in order for the user to re-authenticate. However actual uses a service worker pattern where the application code is cached and all requests are served by the worker. This means that reloading the page in the browser does not actually result in a http request to the backend server; which means that that request cannot be redirected to authenticate. This results in an invalid authentication session and API queries to the backend failling because they are redirecting to auth pages.
This PR adds a button in the advanced settings section that un-registers the service worker handling the routing and then reloads the page. This forces the page to be requeried from the backend server which is then able to be redirected to the authentication page.I've tested this functionality on web, mobile browser, and also iphone PWA and it works as expected.
I've got a couple things I want to check on my implementation:
This functionality isn't relevant on electron. I have followed the pattern that the ResetSync follows by disabling the button if we're on electron. I considered also completely hiding the setting when on electron. Which would be preferable?I couldn't think of a solution that was less of a workaround than this. Maybe this reloading could be triggered if an API query gets a 302 to a configurable path? e.g if/sync/sync
gets redirected uselessly toauth.mydomain.com
then we trigger reloading the whole app so that the user can re-auth? I feel I don't know the full consequences of this solution though. Does anyone have any thoughts on a more automatic solution that will work in a general and/or configurable way?Edit: After feedback I re-implemented the solution to wrap the API fetch so that if any API call is redirected the application is reloaded.