fix(web):update auth token consumers

This commit is contained in:
Anish Sarkar 2026-06-23 12:57:01 +05:30
parent 411bb0019e
commit 71045e552d
4 changed files with 173 additions and 103 deletions

View file

@ -3,17 +3,18 @@
import { useEffect } from "react";
import { useGlobalLoadingEffect } from "@/hooks/use-global-loading";
import { searchSpacesApiService } from "@/lib/apis/search-spaces-api.service";
import { getAndClearRedirectPath, setBearerToken, setRefreshToken } from "@/lib/auth-utils";
import { getAndClearRedirectPath } from "@/lib/auth-utils";
import { buildBackendUrl } from "@/lib/env-config";
import { trackLoginSuccess } from "@/lib/posthog/events";
interface TokenHandlerProps {
redirectPath?: string; // Default path to redirect after storing token (if no saved path)
tokenParamName?: string; // Name of the URL parameter containing the token
tokenParamName?: string; // Deprecated: tokens are no longer read from URLs
}
/**
* Client component that extracts a token from URL parameters and stores it in localStorage
* After storing the token, it redirects the user back to the page they were on before
* Client component that finalizes a cookie session after OAuth/local login.
* After confirming the session, it redirects the user back to the page they were on before
* being redirected to login (if available), or to the default redirectPath.
*
* @param redirectPath - Default path to redirect after storing token (default: '/dashboard')
@ -21,7 +22,7 @@ interface TokenHandlerProps {
*/
const TokenHandler = ({
redirectPath = "/dashboard",
tokenParamName = "token",
tokenParamName: _tokenParamName = "token",
}: TokenHandlerProps) => {
// Always show loading for this component - spinner animation won't reset
useGlobalLoadingEffect(true);
@ -30,51 +31,47 @@ const TokenHandler = ({
if (typeof window === "undefined") return;
const run = async () => {
const params = new URLSearchParams(window.location.search);
const token = params.get(tokenParamName);
const refreshToken = params.get("refresh_token");
if (token) {
try {
const alreadyTracked = sessionStorage.getItem("login_success_tracked");
if (!alreadyTracked) {
trackLoginSuccess("google");
}
sessionStorage.removeItem("login_success_tracked");
setBearerToken(token);
if (refreshToken) {
setRefreshToken(refreshToken);
}
// Auto-set active search space in desktop if not already set
if (window.electronAPI?.getActiveSearchSpace) {
try {
const stored = await window.electronAPI.getActiveSearchSpace();
if (!stored) {
const spaces = await searchSpacesApiService.getSearchSpaces();
if (spaces?.length) {
await window.electronAPI.setActiveSearchSpace?.(String(spaces[0].id));
}
}
} catch {
// non-critical
}
}
const savedRedirectPath = getAndClearRedirectPath();
const finalRedirectPath = savedRedirectPath || redirectPath;
window.location.href = finalRedirectPath;
} catch (error) {
console.error("Error storing token in localStorage:", error);
window.location.href = redirectPath;
try {
const sessionResponse = await fetch(buildBackendUrl("/auth/session"), {
credentials: "include",
});
if (!sessionResponse.ok) {
window.location.href = "/login";
return;
}
const alreadyTracked = sessionStorage.getItem("login_success_tracked");
if (!alreadyTracked) {
trackLoginSuccess("google");
}
sessionStorage.removeItem("login_success_tracked");
// Auto-set active search space in desktop if not already set
if (window.electronAPI?.getActiveSearchSpace) {
try {
const stored = await window.electronAPI.getActiveSearchSpace();
if (!stored) {
const spaces = await searchSpacesApiService.getSearchSpaces();
if (spaces?.length) {
await window.electronAPI.setActiveSearchSpace?.(String(spaces[0].id));
}
}
} catch {
// non-critical
}
}
const savedRedirectPath = getAndClearRedirectPath();
const finalRedirectPath = savedRedirectPath || redirectPath;
window.location.href = finalRedirectPath;
} catch (error) {
console.error("Error finalizing session:", error);
window.location.href = redirectPath;
}
};
run();
}, [tokenParamName, redirectPath]);
}, [redirectPath]);
// Return null - the global provider handles the loading UI
return null;

View file

@ -2,16 +2,17 @@
import { useRouter } from "next/navigation";
import { useEffect } from "react";
import { getBearerToken } from "@/lib/auth-utils";
import { useSession } from "@/hooks/use-session";
export function AuthRedirect() {
const router = useRouter();
const session = useSession();
useEffect(() => {
if (getBearerToken()) {
if (session.status === "authenticated") {
router.replace("/dashboard");
}
}, [router]);
}, [router, session.status]);
return null;
}

View file

@ -1,8 +1,11 @@
"use client";
import { useAtomValue } from "jotai";
import { usePathname } from "next/navigation";
import { useEffect, useRef } from "react";
import { currentUserAtom } from "@/atoms/user/user-query.atoms";
import { useSession } from "@/hooks/use-session";
import { isPublicRoute } from "@/lib/auth-utils";
import { identifyUser, resetUser } from "@/lib/posthog/events";
/**
@ -12,7 +15,15 @@ import { identifyUser, resetUser } from "@/lib/posthog/events";
*
* This should be rendered inside the PostHogProvider.
*/
export function PostHogIdentify() {
function PostHogReset() {
useEffect(() => {
resetUser();
}, []);
return null;
}
function PostHogUserIdentify() {
const { data: user, isSuccess, isError } = useAtomValue(currentUserAtom);
const previousUserIdRef = useRef<string | null>(null);
@ -47,3 +58,27 @@ export function PostHogIdentify() {
// This component doesn't render anything
return null;
}
function SessionGatedPostHogIdentify() {
const session = useSession();
if (session.status === "loading") {
return null;
}
if (session.status === "unauthenticated") {
return <PostHogReset />;
}
return <PostHogUserIdentify />;
}
export function PostHogIdentify() {
const pathname = usePathname();
if (isPublicRoute(pathname)) {
return <PostHogReset />;
}
return <SessionGatedPostHogIdentify />;
}