From 432c5f2817d9d6be28dfaec780d88cf48a6418b2 Mon Sep 17 00:00:00 2001 From: kolaente Date: Thu, 9 Apr 2026 11:52:24 +0200 Subject: [PATCH] fix: include type in checkAuth's same-user skip check MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Users and link shares share the same numeric id space in JWTs. When a logged-in user opened a link share whose id happened to match their own user id, checkAuth() would see `info.value.id === jwtUser.id` and skip `setUser()`, leaving `info.value.type` as USER even though the new token was a LINK_SHARE. As a result, `authLinkShare` never flipped to true and the router guard bounced between /share/:hash/auth and the project view, stranding the user on an empty NoAuthWrapper shell. Compare on type as well so USER→LINK_SHARE transitions always replace the user object. Refs #2546 --- frontend/src/stores/auth.ts | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/frontend/src/stores/auth.ts b/frontend/src/stores/auth.ts index 94f568885..8e8d5760e 100644 --- a/frontend/src/stores/auth.ts +++ b/frontend/src/stores/auth.ts @@ -324,10 +324,21 @@ export const useAuthStore = defineStore('auth', () => { if (isAuthenticated) { // Only set user from JWT if we don't already have a fully loaded - // user with the same ID. The JWT lacks fields like `name`, so - // overwriting a complete user object causes a visible flash - // where the display name briefly reverts to the username. - if (info.value === null || info.value.id !== jwtUser.id) { + // user with the same ID *and* type. The JWT lacks fields like + // `name`, so overwriting a complete user object causes a visible + // flash where the display name briefly reverts to the username. + // Comparing on type as well is essential: regular users and link + // shares share the same numeric ID space, so a USER and a + // LINK_SHARE can have the same `id`. Without the type check, a + // logged-in user opening a link share whose id collides with + // their user id would keep the USER `info.value` and never flip + // `authLinkShare` to true, causing the router guard to bounce + // between /share/:hash/auth and the project view forever. + if ( + info.value === null || + info.value.id !== jwtUser.id || + info.value.type !== jwtUser.type + ) { setUser(jwtUser, false) } else { // Always keep exp in sync so token renewal checks stay accurate