From cfea3aba34a45fa4159022e5327f514415525158 Mon Sep 17 00:00:00 2001 From: "Calum H." Date: Tue, 4 Aug 2026 15:29:03 +0100 Subject: [PATCH] fix: mc account logout on stale (#6986) --- apps/app-frontend/src/pages/Skins.vue | 1 + packages/app-lib/src/api/minecraft_auth.rs | 2 +- packages/app-lib/src/state/minecraft_auth.rs | 37 ++++++++++++++++++++ 3 files changed, 39 insertions(+), 1 deletion(-) diff --git a/apps/app-frontend/src/pages/Skins.vue b/apps/app-frontend/src/pages/Skins.vue index 6c89f34712..f6a9282bf6 100644 --- a/apps/app-frontend/src/pages/Skins.vue +++ b/apps/app-frontend/src/pages/Skins.vue @@ -1038,6 +1038,7 @@ async function checkUserChanges() { try { const defaultId = await get_default_user() if (defaultId !== currentUserId.value) { + await accountsCard.value?.refreshValues() await loadCurrentUser() await loadCapes() await loadSkins() diff --git a/packages/app-lib/src/api/minecraft_auth.rs b/packages/app-lib/src/api/minecraft_auth.rs index 931b8e75bb..a347d24d68 100644 --- a/packages/app-lib/src/api/minecraft_auth.rs +++ b/packages/app-lib/src/api/minecraft_auth.rs @@ -39,7 +39,7 @@ pub async fn finish_login( #[tracing::instrument] pub async fn get_default_user() -> crate::Result> { let state = State::get().await?; - let user = Credentials::get_active(&state.pool).await?; + let user = Credentials::get_default_credential(&state.pool).await?; Ok(user.map(|user| user.offline_profile.id)) } diff --git a/packages/app-lib/src/state/minecraft_auth.rs b/packages/app-lib/src/state/minecraft_auth.rs index c021a239d2..b835ad439d 100644 --- a/packages/app-lib/src/state/minecraft_auth.rs +++ b/packages/app-lib/src/state/minecraft_auth.rs @@ -79,6 +79,26 @@ pub enum MinecraftAuthenticationError { NoUserHash, } +#[derive(Deserialize)] +struct OAuthErrorResponse { + error: String, +} + +impl MinecraftAuthenticationError { + fn is_invalid_grant(&self) -> bool { + matches!( + self, + Self::DeserializeResponse { + step: MinecraftAuthStep::RefreshOAuthToken, + raw, + status_code: StatusCode::BAD_REQUEST, + .. + } if serde_json::from_str::(raw) + .is_ok_and(|response| response.error == "invalid_grant") + ) + } +} + #[derive(Serialize, Deserialize, Debug)] pub struct MinecraftLoginFlow { pub verifier: String, @@ -466,6 +486,23 @@ impl Credentials { return Ok(Some(creds)); } + if matches!( + &*err.raw, + ErrorKind::MinecraftAuthenticationError(source) + if source.is_invalid_grant() + ) { + Self::remove(creds.offline_profile.id, exec).await?; + + if let Some((_, mut user)) = + Self::get_all(exec).await?.into_iter().next() + { + user.active = true; + user.upsert(exec).await?; + } + + return Ok(None); + } + Err(err) } }