Arksine / moonraker

Web API Server for Klipper
https://moonraker.readthedocs.io
GNU General Public License v3.0
1.05k stars 406 forks source link

ServerError: JWT Expired (Constantly having to log in) #793

Closed samwiseg0 closed 8 months ago

samwiseg0 commented 8 months ago

What happened

In one of the more recent updates, I am having to constantly log into moonraker. This even extends to actively using the fluidd interface and clicking on a config file to edit it and being prompted to login again.

I have not had time to rollback one commit at a time to see which specific one broke it but it has been a change within the last 4-8 weeks as of writing.

Logs attached. moonraker-1.log

Edit: To add, I have this problem on multiple printers. The other printer has a fresh mainailos install. With fresh installs of all other dependencies. I have tried accessing fluidd/nginx directly on the pi with the same results. I have also tested with nothing else talking to moonraker such as mooncord etc.

Happy to perform any other debug needed.

Client

Fluidd

Browser

Chrome, Safari, Other or N/A

How to reproduce

Configure moonraker to require auth on non trusted clients. Keep the window active for at least an hour or 2. Navigate to a config file. Try to edit. You will be prompted to login again.

Additional information

No response

Arksine commented 8 months ago

Thanks. Commit a23187b4afa632da8a90cb9eae83f0f6a5eec903 should resolve this.

To provide an explanation on what happened I need to explain some basics about how JWT authentication works. When a user logs in they are provided two tokens, an access token and a refresh token. The access token expires in one hour, the refresh token expiration is configurable in the [authorization] section. The refresh token is used to fetch new access tokens when an access token expires. When a refresh token expires the user must log in.

To make this work we need to allow access to a few endpoints without authentication, specifically the endpoints used to login and refresh. When a frontend requests one of these endpoints an access token is not required. That said, if an access token is provided in the request then Moonraker should validate it and return a 401 if its invalid. That is what is happening here, Fluidd is providing an expired access token when it attempts to request a new one via the refresh endpoint.

Previously Moonraker bypassed token validation on endpoints that don't require authentication. I recently "fixed" this, and this is the source of the regression. Since Moonraker previously allowed this behavior, I have made a change to ignore the expiration time on access tokens received from a request that doesn't require validation.

samwiseg0 commented 8 months ago

Awesome! thank you for the fix and explanation.

As a side note should we open an issue with fluidd and have them correct this behavior?

Will your fix have a negative impact on security of moonraker?

Arksine commented 8 months ago

The security impact is minimal to non-existent given that unauthenticated access is allowed on these endpoints. Moonraker still validates all of the other parts of the token (such as the signature), so it knows that Moonraker issued the token even though its expired. This is more about correctness and informing the client that its trying to use an invalid token.

Its probably easier to tag @pedrolamas here than create an issue on Fluidd. If he wants to modify the refresh request to exclude the access token its ok, if he doesn't I don't think its harmful.

samwiseg0 commented 8 months ago

Those were my thoughts as well. I just wanted to confirm.

I have updated all my printers. Will report back after I have used it a bit today.

Thanks again!

pedrolamas commented 8 months ago

Thanks for the tag, I will take a look and see what we can do to improve this situation.

From a quick read, all we need to do from Fluidd side is not send any token to the login or refresh endpoints, so I think that should be easy to fix (famous last words!)

Arksine commented 8 months ago

Yeah. The login doesn't seem to receive an access token since it it didn't fail prior to https://github.com/Arksine/moonraker/commit/a23187b4afa632da8a90cb9eae83f0f6a5eec903. The /access/refresh_jwt endpoint is receiving an access token.

samwiseg0 commented 8 months ago

I can confirm this commit did patch the issue.

Arksine commented 8 months ago

Thanks.

pedrolamas commented 8 months ago

FWIW, I've now merged a fix for this on Fluidd side to ensure we do not send the Authorization header on /access/login and /access/refresh_jwt endpoints.