diff --git a/client/src/app/auth/login/page.tsx b/client/src/app/auth/login/page.tsx index 1da9b35..921f62f 100644 --- a/client/src/app/auth/login/page.tsx +++ b/client/src/app/auth/login/page.tsx @@ -34,6 +34,7 @@ const LoginPage = () => { const { setAccessToken, setUser, accessToken, user } = useAuth(); const { isInitialized, isLoading: authLoading } = useAuthContext(); const [showPassword, setShowPassword] = useState(false); + const [isOAuthProcessing, setIsOAuthProcessing] = useState(false); // Get redirect path using AuthDomain const getRedirectPath = () => { @@ -77,8 +78,50 @@ const LoginPage = () => { } }, [isInitialized, authLoading, accessToken, user, router]); + useEffect(() => { + const completeOAuthLogin = async () => { + if (!isInitialized || authLoading || accessToken || user) { + return; + } + + const urlParams = new URLSearchParams(window.location.search); + if (urlParams.get('oauth') !== 'success') { + return; + } + + setIsOAuthProcessing(true); + try { + const refreshResponse = await api.post('/auth/refresh', {}, { withCredentials: true }); + const refreshedAccessToken = + refreshResponse.data?.data?.accessToken || refreshResponse.data?.accessToken; + + if (!refreshedAccessToken) { + throw new Error('OAuth refresh did not return an access token'); + } + + setAccessToken(refreshedAccessToken); + + const profileResponse = await api.get('/auth/me'); + const userProfile = profileResponse.data?.data; + if (userProfile) { + setUser(userProfile); + } + + const redirectPath = getRedirectPath(); + AuthDomain.clearRedirectPath(); + router.push(redirectPath); + } catch (error: unknown) { + handleError(error, 'OAuth Login'); + } finally { + setIsOAuthProcessing(false); + } + }; + + completeOAuthLogin(); + }, [isInitialized, authLoading, accessToken, user, setAccessToken, setUser, router, handleError]); + // Show loading while auth is initializing - if (!isInitialized || authLoading) { + if (!isInitialized || authLoading || isOAuthProcessing) { return ; } diff --git a/server/src/controllers/auth.controller.ts b/server/src/controllers/auth.controller.ts index bd1b3ac..e91e070 100644 --- a/server/src/controllers/auth.controller.ts +++ b/server/src/controllers/auth.controller.ts @@ -109,6 +109,13 @@ export const logout = async (req: Request, res: Response) => { sameSite: "strict", path: "/api/v1/auth", }); + // Backward-compatibility cleanup for previously issued root-path cookies. + res.clearCookie("refreshToken", { + httpOnly: true, + secure: process.env.NODE_ENV === "production", + sameSite: "strict", + path: "/", + }); return sendSuccess(res, 200, "Logged out successfully"); }; @@ -155,6 +162,21 @@ export const refresh = async (req: Request, res: Response) => { const stored: Token | null = await Token.findOne({ where: { refreshToken: token }, }); + if (!stored) { + // Clear potentially stale/legacy refresh cookies so the next login starts cleanly. + res.clearCookie("refreshToken", { + httpOnly: true, + secure: process.env.NODE_ENV === "production", + sameSite: "strict", + path: "/api/v1/auth", + }); + res.clearCookie("refreshToken", { + httpOnly: true, + secure: process.env.NODE_ENV === "production", + sameSite: "strict", + path: "/", + }); + } throwIf(!stored, 401, "Refresh token revoked"); const newAccessToken = jwt.sign({ id: payload.id }, process.env.JWT_SECRET!, { diff --git a/server/src/controllers/social.controller.ts b/server/src/controllers/social.controller.ts index e724da5..1d4cfc9 100644 --- a/server/src/controllers/social.controller.ts +++ b/server/src/controllers/social.controller.ts @@ -34,7 +34,14 @@ export const handleOAuthSuccess = async (req: Request, res: Response) => { httpOnly: true, secure: process.env.NODE_ENV === "production", sameSite: "strict", + path: "/api/v1/auth", maxAge: REFRESH_EXPIRY_MS, }); + + const clientUrl = process.env.CLIENT_URL; + if (clientUrl) { + return res.redirect(`${clientUrl}/auth/login?oauth=success`); + } + return sendSuccess(res, 200, "OAuth login successful", { accessToken }); }; diff --git a/server/src/routes/auth.routes.ts b/server/src/routes/auth.routes.ts index a750788..21c8c99 100644 --- a/server/src/routes/auth.routes.ts +++ b/server/src/routes/auth.routes.ts @@ -30,7 +30,6 @@ authRouter.get( passport.authenticate("google", { session: false, failureRedirect: "/login", - successRedirect: process.env.CLIENT_URL, }), handleOAuthSuccess ); @@ -45,7 +44,6 @@ authRouter.get( passport.authenticate("github", { session: false, failureRedirect: "/login", - successRedirect: process.env.CLIENT_URL, }), handleOAuthSuccess );