From 4f36d65b0594e15159409445e522c310a9870daf Mon Sep 17 00:00:00 2001 From: JOY <5027251+JOY@users.noreply.github.com> Date: Wed, 23 Sep 2026 16:54:43 +0700 Subject: [PATCH] fix(dos-id): refresh the IdP avatar on every login instead of once The JIT avatar sync skipped users who already had an avatar (!user.avatarImageId), so an avatar changed upstream in DOS Me never propagated to Sign through login - the first avatar seen was frozen forever. The user.updated webhook path already refreshed unconditionally, making the two paths inconsistent. Drop the guard: when the IdP provides an avatar URL, it is the source of truth and replaces the stored avatar on each login (the sync helper already swaps the image and deletes the old row, is SSRF-guarded, and fails soft so logins never break on avatar errors). With no IdP URL, locally-uploaded avatars are left untouched. --- .../lib/server-only/dos-id/sync-dos-profile.ts | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/packages/lib/server-only/dos-id/sync-dos-profile.ts b/packages/lib/server-only/dos-id/sync-dos-profile.ts index d28d7dfbcb..c51c5acf80 100644 --- a/packages/lib/server-only/dos-id/sync-dos-profile.ts +++ b/packages/lib/server-only/dos-id/sync-dos-profile.ts @@ -415,16 +415,13 @@ export const syncDosProfileAndOrgs = async ({ }); } - // 2. Sync Avatar if URL is provided + // 2. Sync Avatar if URL is provided. The IdP avatar is the source of truth + // (same policy as the name above): refresh on every login so upstream + // avatar changes propagate - the old skip-if-exists guard froze the first + // avatar forever. A locally-uploaded avatar is only replaced when the IdP + // actually provides a URL; with no IdP avatar the local upload stays. if (avatarUrl) { - const user = await prisma.user.findUnique({ - where: { id: userId }, - select: { avatarImageId: true }, - }); - - if (!user?.avatarImageId) { - await syncUserAvatarFromUrl(userId, avatarUrl); - } + await syncUserAvatarFromUrl(userId, avatarUrl); } // 3. JIT Provision Organizations from claims OR shared PostgreSQL DB fallback