From 3b85ff3bdf4fb053b103070646811bc990c0e70a Mon Sep 17 00:00:00 2001 From: Igor Monadical Date: Tue, 9 Sep 2025 16:27:46 -0400 Subject: [PATCH] fix: auth post (#626) Co-authored-by: Igor Loskutov --- www/app/lib/AuthProvider.tsx | 1 + www/app/lib/apiClient.tsx | 26 ++++++++++++++++++++++---- 2 files changed, 23 insertions(+), 4 deletions(-) diff --git a/www/app/lib/AuthProvider.tsx b/www/app/lib/AuthProvider.tsx index 6c09926b..67c440da 100644 --- a/www/app/lib/AuthProvider.tsx +++ b/www/app/lib/AuthProvider.tsx @@ -88,6 +88,7 @@ export function AuthProvider({ children }: { children: React.ReactNode }) { }; // not useEffect, we need it ASAP + // apparently, still no guarantee this code runs before mutations are fired configureApiAuth( contextValue.status === "authenticated" ? contextValue.accessToken : null, ); diff --git a/www/app/lib/apiClient.tsx b/www/app/lib/apiClient.tsx index 133db7c3..4bedaebe 100644 --- a/www/app/lib/apiClient.tsx +++ b/www/app/lib/apiClient.tsx @@ -14,9 +14,27 @@ export const client = createClient({ baseUrl: API_URL, }); -// has to be called BEFORE $api is created with createFetchClient(client) or onRequest doesn't fire [at least for POST] +const waitForAuthTokenDefinitivePresenceOrAbscence = async () => { + let tries = 0; + let time = 0; + const STEP = 100; + while (currentAuthToken === undefined) { + await new Promise((resolve) => setTimeout(resolve, STEP)); + time += STEP; + tries++; + // most likely first try is more than enough, if it's more there's already something weird happens + if (tries > 10) { + // even when there's no auth assumed at all, we probably should explicitly call configureApiAuth(null) + throw new Error( + `Could not get auth token definitive presence/absence in ${time}ms. not calling configureApiAuth?`, + ); + } + } +}; + client.use({ - onRequest({ request }) { + async onRequest({ request }) { + await waitForAuthTokenDefinitivePresenceOrAbscence(); if (currentAuthToken) { request.headers.set("Authorization", `Bearer ${currentAuthToken}`); } @@ -35,9 +53,9 @@ client.use({ export const $api = createFetchClient(client); -let currentAuthToken: string | null | undefined = null; +let currentAuthToken: string | null | undefined = undefined; // the function contract: lightweight, idempotent -export const configureApiAuth = (token: string | null | undefined) => { +export const configureApiAuth = (token: string | null) => { currentAuthToken = token; };