diff --git a/src/api/auth.ts b/src/api/auth.ts index 0505d7e..d35b9d6 100644 --- a/src/api/auth.ts +++ b/src/api/auth.ts @@ -291,7 +291,17 @@ export const authApi = { }, pollDeepLinkToken: async (token: string): Promise => { - const response = await apiClient.post('/cabinet/auth/deeplink/poll', { token }); + // validateStatus: only treat 200 as success. + // Server returns 202 for "pending" and 410 for "expired" — + // these must reject so the polling catch-block can handle them. + // Without this, axios resolves on 202 (it's 2xx), causing + // loginWithDeepLink to set undefined tokens + isAuthenticated=true, + // which triggers checkAdminStatus() → 401 → safeRedirectToLogin() → infinite reload. + const response = await apiClient.post( + '/cabinet/auth/deeplink/poll', + { token }, + { validateStatus: (status) => status === 200 }, + ); return response.data; }, diff --git a/src/api/client.ts b/src/api/client.ts index abe6eb8..57f9116 100644 --- a/src/api/client.ts +++ b/src/api/client.ts @@ -71,6 +71,8 @@ const AUTH_ENDPOINTS = [ '/cabinet/auth/oauth/', '/cabinet/auth/merge/', '/cabinet/auth/account/link/server-complete', + '/cabinet/auth/deeplink/', + '/cabinet/auth/login/auto', '/cabinet/landing/', ]; diff --git a/src/store/auth.ts b/src/store/auth.ts index 2ff82a8..81b9602 100644 --- a/src/store/auth.ts +++ b/src/store/auth.ts @@ -74,6 +74,9 @@ export const useAuthStore = create()( clearCampaignBonus: () => set({ pendingCampaignBonus: null }), setTokens: (accessToken, refreshToken) => { + if (!accessToken || !refreshToken) { + throw new Error('Invalid tokens: cannot store empty credentials'); + } tokenStorage.setTokens(accessToken, refreshToken); set({ accessToken, @@ -321,6 +324,9 @@ export const useAuthStore = create()( loginWithDeepLink: async (token) => { const response = await authApi.pollDeepLinkToken(token); + if (!response.access_token || !response.refresh_token) { + throw new Error('Invalid auth response: missing tokens'); + } tokenStorage.setTokens(response.access_token, response.refresh_token); set({ accessToken: response.access_token, diff --git a/src/utils/token.ts b/src/utils/token.ts index 11cc932..2b4b2af 100644 --- a/src/utils/token.ts +++ b/src/utils/token.ts @@ -258,6 +258,8 @@ export function getAndClearReturnUrl(): string | null { export function safeRedirectToLogin(): void { if (typeof window !== 'undefined') { + // Guard: don't redirect if already on /login to prevent infinite reload loops + if (window.location.pathname === '/login') return; saveReturnUrl(); window.location.href = '/login'; }