diff --git a/apps/as/app/api/auth/logout/route.ts b/apps/as/app/api/auth/logout/route.ts new file mode 100644 index 000000000..d040a8f49 --- /dev/null +++ b/apps/as/app/api/auth/logout/route.ts @@ -0,0 +1,18 @@ +import { cookies } from "next/headers"; +import { NextResponse } from "next/server"; + +import { + ACCESS_TOKEN, + AUTH_USER_ID, + CLAIM_NAME, + REFRESH_TOKEN, +} from "@/shared/config"; + +export async function POST() { + const cookieStore = await cookies(); + cookieStore.delete(ACCESS_TOKEN); + cookieStore.delete(REFRESH_TOKEN); + cookieStore.delete(AUTH_USER_ID); + cookieStore.delete(CLAIM_NAME); + return NextResponse.json({ message: "Logged out" }, { status: 200 }); +} diff --git a/apps/as/src/app/layouts/base-layout.tsx b/apps/as/src/app/layouts/base-layout.tsx index fc84a5e3e..e0c1c9bb0 100644 --- a/apps/as/src/app/layouts/base-layout.tsx +++ b/apps/as/src/app/layouts/base-layout.tsx @@ -5,10 +5,11 @@ import { usePathname, useRouter } from "next/navigation"; import { useQueryClient } from "@tanstack/react-query"; -import { useMenuStore } from "@/shared/lib"; -import { PageLayout } from "@/shared/ui/page-layout"; +import { authService } from "@/entities/auth"; import type { MenuItem } from "@/entities/menu"; import { BaseLayout } from "@common/components"; +import { useMenuStore } from "@/shared/lib"; +import { PageLayout } from "@/shared/ui/page-layout"; interface BaseLayoutWrapperProps { children: React.ReactNode; @@ -32,6 +33,7 @@ export function BaseLayoutWrapper({ children }: BaseLayoutWrapperProps) { return ( diff --git a/apps/as/src/entities/auth/api/auth-service.ts b/apps/as/src/entities/auth/api/auth-service.ts index 0c1730054..914b7e13e 100644 --- a/apps/as/src/entities/auth/api/auth-service.ts +++ b/apps/as/src/entities/auth/api/auth-service.ts @@ -1,7 +1,7 @@ -import { ACCESS_TOKEN, AUTH_USER_ID, CLAIM_NAME, ENDPOINT } from "@/shared/config"; +import { ACCESS_TOKEN, AUTH_LOGIN_REDIRECT_URL, AUTH_USER_ID, CLAIM_NAME, ENDPOINT } from "@/shared/config"; import { getRemainingMs } from "@common/auth"; -import { clearAuthToken, setToken, setupRefreshTimer } from "../lib/token-manager"; +import { clearAuthToken, removeToken, setToken, setupRefreshTimer } from "../lib/token-manager"; import type { AuthPayload, AuthService } from "../model/auth-interface"; async function login(payload: AuthPayload): Promise { @@ -66,9 +66,22 @@ async function silentRefresh(): Promise { } async function logout(): Promise { + try { + await fetch("/api/auth/logout", { + method: "POST", + credentials: "include", + }); + } catch (error) { + console.error("Logout API failed:", error); + } + clearAuthToken(); + removeToken("site-id-key"); + removeToken("site-theme-key"); + if (typeof window !== "undefined") { window.dispatchEvent(new CustomEvent("auth:logout")); + window.location.href = AUTH_LOGIN_REDIRECT_URL; } } diff --git a/apps/as/src/entities/auth/model/auth-interface.ts b/apps/as/src/entities/auth/model/auth-interface.ts index fb6e10630..86b6453e5 100644 --- a/apps/as/src/entities/auth/model/auth-interface.ts +++ b/apps/as/src/entities/auth/model/auth-interface.ts @@ -1,10 +1 @@ -export interface AuthPayload { - userId: string; - password: string; -} - -export interface AuthService { - login(payload: AuthPayload): Promise; - silentRefresh(): Promise; - logout(): Promise; -} +export type { AuthPayload, AuthService } from "@common/auth";