Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion apps/web/src/app/login/_hooks/usePostGuestLogin.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import { WEBBRIDGE_MESSAGE_TYPE } from '@piki/core';
import { useMutation, useQueryClient } from '@tanstack/react-query';
import { useRouter } from 'next/navigation';

import { setCookie } from '@/utils/cookie';
import { getLoginRedirectPath } from '@/utils/loginRedirect';
import { isWebview } from '@/utils/webBridge';
import { WebBridge, isWebview } from '@/utils/webBridge';

import { postGuestLogin } from '../_apis/postGuestLogin';

Expand All @@ -19,6 +20,10 @@ export const usePostGuestLogin = () => {
if (isWebview() && data.accessToken && data.refreshToken) {
setCookie('access_token', data.accessToken, { minutes: 15 });
setCookie('refresh_token', data.refreshToken, { days: 14 });
WebBridge.postMessage({
type: WEBBRIDGE_MESSAGE_TYPE.WEB_REQ_TOKEN_REFRESHED,
payload: { accessToken: data.accessToken, refreshToken: data.refreshToken },
});
}

router.replace(getLoginRedirectPath());
Expand Down
20 changes: 18 additions & 2 deletions apps/web/src/app/login/page.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,10 @@
import { cookies } from 'next/headers';
import { redirect } from 'next/navigation';

import PikiLogo from '@/assets/images/piki-logo.svg';
import { ROUTES } from '@/consts/route';
import { isTokenValid } from '@/utils/auth';
import { isValidLoginRedirectPath } from '@/utils/loginRedirect';

import LoginButtons from './_components/LoginButtons';

Expand All @@ -7,7 +13,17 @@ type LoginPageProps = {
};

async function LoginPage({ searchParams }: LoginPageProps) {
const { redirect, action } = await searchParams;
const { redirect: redirectParam, action } = await searchParams;

// 이미 유효한 세션이 있으면 로그인 페이지를 건너뜀 (게스트·소셜 모두)
// action이 있으면 세션 만료/소셜 오류 등 명시적 케이스 → 건너뛰지 않음
if (!action) {
const cookieStore = await cookies();
const accessToken = cookieStore.get('access_token')?.value;
if (accessToken && isTokenValid(accessToken)) {
redirect(isValidLoginRedirectPath(redirectParam) ? redirectParam : ROUTES.HOME);
Comment on lines +20 to +24

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🗄️ Data Integrity & Integration | 🟠 Major | 🏗️ Heavy lift

refresh_token 복원 실패 전에는 새 게스트 로그인을 노출하지 마세요.

현재 /login 스킵 조건이 access_token 유효성만 봅니다. usePostGuestLogin은 access 쿠키를 15분, refresh 쿠키를 14일로 저장하므로, 앱 재시작 시 access만 만료된 상태에서는 Line 38의 LoginButtons가 렌더링되고 게스트 버튼이 새 게스트 세션을 만들 수 있습니다. refresh_token으로 세션 복원을 먼저 시도하고 실패한 경우에만 로그인 UI/게스트 생성을 허용해 주세요.

Also applies to: 38-38

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/web/src/app/login/page.tsx` around lines 20 - 24, The `/login` flow in
`page.tsx` only checks `access_token` in the `action` guard, which can expose
`LoginButtons` and allow a new guest session before session restoration is
attempted. Update the login-page logic to first try restoring the session with
`refresh_token` (or the existing refresh-based restore path), and only render
the login UI or allow guest login when that restore fails. Keep the change
localized around the `page` component and the `LoginButtons` rendering so the
guest button cannot create a new session while a valid refresh session still
exists.

}
}

return (
<div className="flex min-h-dvh flex-col items-center bg-gray-50 px-4 pt-padding-top pb-10">
Expand All @@ -19,7 +35,7 @@ async function LoginPage({ searchParams }: LoginPageProps) {
</div>

<div className="mt-[90px] w-full">
<LoginButtons redirect={redirect ?? null} action={action ?? null} />
<LoginButtons redirect={redirectParam ?? null} action={action ?? null} />
</div>
</div>
);
Expand Down
Loading