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
29 changes: 23 additions & 6 deletions frontend/server/index.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import fs from 'node:fs';
import https from 'node:https';
import path from 'node:path';
import process from 'node:process';
import { fileURLToPath } from 'node:url';
Expand Down Expand Up @@ -29,9 +30,7 @@ const addMiddleware = async () => {
}
};

const createServer = async () =>{
await addMiddleware();

const serveHTML = async () => {
app.use('*', async (req, res) => {
try {
const url = req.originalUrl.replace(base, '');
Expand All @@ -54,10 +53,28 @@ const createServer = async () =>{
res.status(500).end(e.stack);
}
});
};

const createServer = async () =>{
await addMiddleware();
await serveHTML();

app.listen(port);
// eslint-disable-next-line no-console
console.log(`\nServer running at \x1b[33mhttp://localhost:${port}\x1b[0m \n`);
if (!isProduction) {
const httpsOptions = {
key: fs.readFileSync(path.resolve(dirname, '../mkcert/key.pem')),
cert: fs.readFileSync(path.resolve(dirname, '../mkcert/cert.pem')),
};

https.createServer(httpsOptions, app).listen(port, () => {
// eslint-disable-next-line no-console
console.log(`\n🔐 Dev HTTPS server running at \x1b[33mhttps://localhost:${port}\x1b[0m \n`);
});
} else {
app.listen(port, () => {
// eslint-disable-next-line no-console
console.log(`\n🚀 Prod HTTP server running at \x1b[33mhttp://localhost:${port}\x1b[0m \n`);
});
}
};

createServer();
3 changes: 3 additions & 0 deletions frontend/src/constants/error.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@ export const errorMessages = {
O005: '잘못된 OAuth 사용자 정보예요',
O006: 'refresh 토큰이 만료되었어요',
GC001: '동기화 토큰이 만료되었어요',
RT001: 'refresh 토큰이 없어요',
RT002: 'refresh 토큰이 유효하지 않아요',
RT003: 'refresh 토큰이 만료되었어요',
} as const;

export const DEFAULT_ERROR_MESSAGE = '알 수 없는 오류가 발생했습니다.';
Expand Down
13 changes: 3 additions & 10 deletions frontend/src/layout/GlobalNavBar/index.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@

import { useNavigate } from '@tanstack/react-router';
import { type PropsWithChildren, useEffect, useState } from 'react';
import { type PropsWithChildren } from 'react';

import { Flex } from '@/components/Flex';
import { refresh } from '@/utils/auth';
import { isLogin } from '@/utils/auth';

import BaseContainer from './BaseContainer';
import { LoginLink, MyCalendarLink, NewDiscussionLink } from './buttons';
Expand All @@ -15,19 +15,12 @@ interface GlobalNavBarProps extends PropsWithChildren {

const GlobalNavBar = ({ background = 'white', children }: GlobalNavBarProps) => {
const navigate = useNavigate();
const [isLoggedIn, setIsLoggedIn] = useState(false);

const onClickLogo = () => {
navigate({ to: '/', replace: true });
};

useEffect(() => {
(async () => {
setIsLoggedIn(await refresh());
})();
}, []);

if (!isLoggedIn) return (
if (!isLogin()) return (
<BaseContainer background={background} onClickLogo={onClickLogo}>
<LoginLink />
</BaseContainer>
Expand Down
3 changes: 2 additions & 1 deletion frontend/src/routes/_main.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { createFileRoute, Outlet, redirect } from '@tanstack/react-router';

import MainLayout from '@/layout/MainLayout';
import { isLogin } from '@/utils/auth';
import { isLogin, refresh } from '@/utils/auth';
import { setLastRoutePath } from '@/utils/route';

const Layout = () => (
Expand All @@ -12,6 +12,7 @@ const Layout = () => (

export const Route = createFileRoute('/_main')({
beforeLoad: async ({ location }) => {
await refresh();
if (!isLogin()) {
setLastRoutePath(location.pathname);
throw redirect({ to: '/login' });
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { getLastRoutePath } from '@/utils/route';
const Redirect = () => {
const { loginMutate } = useJWTMutation();
const lastPath = getLastRoutePath();
const params: { code: string } = useSearch({ from: '/oauth/redirect/' });
const params: { code: string } = useSearch({ from: '/oauth/redirect/login/' });
const { code } = params;

useEffect(() => {
Expand All @@ -19,6 +19,6 @@ const Redirect = () => {
return null;
};

export const Route = createFileRoute('/oauth/redirect/')({
export const Route = createFileRoute('/oauth/redirect/login/')({
component: Redirect,
});
2 changes: 1 addition & 1 deletion frontend/src/utils/auth/accessTokenService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,8 @@ export const accessTokenService = {
accessTokenService.setAccessToken(jwtResponse);
return true;
} catch {
// 리프레시 토큰 만료, O006 에러 발생
accessTokenService.clearAccessToken();
return false;
} finally {
// race condition 방지를 위해, 자신이 생성한 promise가 원본 Promise인지 확인 후 null로 초기화
if (refreshPromise === localPromise) {
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/utils/error/HTTPError.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,5 +21,5 @@ export class HTTPError extends Error {
isForbiddenError = () => this.#status === 403;
isTooManyRequestsError = () => this.#status === 429;

isInvalidRefreshTokenError = () => this.#code === 'O006';
isInvalidRefreshTokenError = () => this.#code.startsWith('RT');
}
1 change: 0 additions & 1 deletion frontend/src/utils/fetch/executeFetch.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,6 @@ const buildFetchOptions = (options?: RequestInit): RequestInit => {
const defaultOptions: RequestInit = {
headers,
mode: 'cors',
// accessToken을 쿠키로 관리하기 위한 설정
credentials: 'include',
};

Expand Down