From 84dcfc46b98fbcb7af7bc1455613e4f2eceda0fb Mon Sep 17 00:00:00 2001 From: Vadym Samoilenko Date: Sun, 24 May 2026 19:32:29 +0100 Subject: [PATCH] =?UTF-8?q?fix(auth):=20registration=20bypasses=20email=20?= =?UTF-8?q?gate=20=E2=80=94=20add=20setAuth()=20to=20properly=20init=20Rea?= =?UTF-8?q?ct=20state?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Previously Register.tsx wrote auth_token directly to localStorage without calling setToken/setUser in AuthContext. This made isAuthenticated=true (computed from localStorage) while user=null (React state), so ProtectedRoute's user.email_verified check was never reached. - AuthContext: add setAuth(token, userData) that syncs both localStorage and React state - Register: use setAuth() instead of direct localStorage write - Register: add !registered guard to auto-redirect effect to prevent bypassing check-inbox screen Co-Authored-By: Claude Sonnet 4.6 --- src/contexts/AuthContext.tsx | 10 +++++++++- src/pages/Register.tsx | 10 +++++----- 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/src/contexts/AuthContext.tsx b/src/contexts/AuthContext.tsx index 804d6ba8..17b86a8c 100755 --- a/src/contexts/AuthContext.tsx +++ b/src/contexts/AuthContext.tsx @@ -17,6 +17,7 @@ interface AuthContextType { login: (username: string, password: string) => Promise; logout: () => void; refreshUser: () => Promise; + setAuth: (token: string, userData: User) => void; isAuthenticated: boolean; } @@ -141,6 +142,13 @@ export function AuthProvider({ children }: { children: ReactNode }) { } }; + const setAuth = (accessToken: string, userData: User) => { + localStorage.setItem('auth_token', accessToken); + localStorage.setItem('user', JSON.stringify(userData)); + setToken(accessToken); + setUser(userData); + }; + const refreshUser = async () => { if (!token) return; const validationKey = `token_validated_${token.substring(0, 10)}`; @@ -175,7 +183,7 @@ export function AuthProvider({ children }: { children: ReactNode }) { })(); return ( - + {children} ); diff --git a/src/pages/Register.tsx b/src/pages/Register.tsx index 0f1ce179..afb1be2d 100644 --- a/src/pages/Register.tsx +++ b/src/pages/Register.tsx @@ -123,7 +123,7 @@ function MockPanel() { export default function Register() { const navigate = useNavigate(); const [searchParams] = useSearchParams(); - const { isAuthenticated } = useAuth(); + const { isAuthenticated, setAuth } = useAuth(); const { t } = useTranslation(); const [isLoading, setIsLoading] = useState(false); const [showPassword, setShowPassword] = useState(false); @@ -135,8 +135,8 @@ export default function Register() { const planMeta = planKey ? PLAN_META[planKey] : null; useEffect(() => { - if (isAuthenticated) navigate('/dashboard', { replace: true }); - }, [isAuthenticated, navigate]); + if (isAuthenticated && !registered) navigate('/dashboard', { replace: true }); + }, [isAuthenticated, navigate, registered]); const form = useForm({ resolver: zodResolver(registerSchema), @@ -155,8 +155,8 @@ export default function Register() { }); setRegisteredEmail(values.email); setRegistered(true); - if (res.data.access_token) { - localStorage.setItem('auth_token', res.data.access_token); + if (res.data.access_token && res.data.user) { + setAuth(res.data.access_token, res.data.user); toastService.success(t('auth.toast_account_created'), { description: t('auth.toast_account_created_desc') }); } } catch (err: any) {