fix(webapi): persist the Web API token refreshed mid-session - #743
fix(webapi): persist the Web API token refreshed mid-session#743prefixFelix wants to merge 1 commit into
Conversation
| // `WebApi` keeps its own copy and would save it right back into | ||
| // the config we just cleared. | ||
| crate::webapi::WebApi::global().set_webapi_credentials(None, None); | ||
| data.config.save(); |
There was a problem hiding this comment.
Just a note on these docs, theyre written with reference to the current issue. Unless there is some existing behavior that's present, its not so useful to write the docs in reference to past behavior or a fix we've completed.
There was a problem hiding this comment.
| // `WebApi` keeps its own copy and would save it right back into | |
| // the config we just cleared. | |
| crate::webapi::WebApi::global().set_webapi_credentials(None, None); | |
| data.config.save(); | |
| // `WebApi` holds an in-memory copy of the credentials that it | |
| // persists back to the config on save, so clear it too. | |
| crate::webapi::WebApi::global().set_webapi_credentials(None, None); | |
| data.config.save(); |
| *self.webapi_token.lock() = token; | ||
| } | ||
|
|
||
| /// Install the handle used to send refreshed tokens back to the GUI thread. |
There was a problem hiding this comment.
A bit weird that the gui owns the config right? Do you have any architectural thoughts on what would be better here?
There was a problem hiding this comment.
We could maybe split the toke stuff from the config file into a own token-store?
Token-store would be moved to the core and the config stays in the gui (as it then only holds gui stuff).
Yes I changed the epoch time from |
|
@prefixFelix I'd like to also get this in, can you rebase on the latest changes and test. I'll review post. |
9599e4d to
f991143
Compare
Problem
Spotify rotates the refresh token on every PKCE refresh and revokes the previous one. psst has two refresh paths and only one of them saves the result.
Config::get_or_refresh_webapi_token()runs once at startup and callssave().WebApi::access_token()runs on worker threads for every API call and only updated its in-memory copy. Its comment claimed the durable copy would be "refreshed by Config on the next save", which was never true:save()serializesConfig::webapi_token, a separate field that WebApi never touches. WebApi holds no reference to Config and no way to reach the GUI thread, so it could not persist anything at all.So once a session runs past the one hour mark, WebApi refreshes, Spotify revokes the old token, the replacement lives only in memory, and config.json keeps a corpse. The next launch presents the revoked token and gets
invalid_grant, and so does every launch after that, because nothing ever replaces it. Until you re-authenticate, Web API features stay dead.Follow up
We should type the
invalid_grantresponse.refresh_webapi_token()collapses every failure intoError::OAuthError(String)built from the oauth2 error's Display and for a server response that Display is literally "Server returned error response", discarding the payload. So the log cannot tell a revoked token from a bad client ID or a network blip.