Skip to content

Commit 04cf7a4

Browse files
refactor(web): restructure auth module and add i18n login messages
- Move auth-client.ts and auth.ts to lib/auth/ directory - Extract token utilities to lib/auth/token.ts - Add timeZone (Asia/Seoul) to NextIntlClientProvider and request config - Add login i18n messages for Google, Facebook, GitHub providers (en/ko/ja) Amp-Thread-ID: https://ampcode.com/threads/T-019bd002-1ab6-77c9-a93b-ae0e9bfd95e8 Co-authored-by: Amp <amp@ampcode.com>
1 parent baabe9c commit 04cf7a4

10 files changed

Lines changed: 74 additions & 51 deletions

File tree

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
import { toNextJsHandler } from "better-auth/next-js";
2-
import { auth } from "@/lib/auth";
2+
import { auth } from "@/lib/auth/auth-server";
33

44
export const { GET, POST } = toNextJsHandler(auth.handler);

apps/web/src/app/providers.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import {
1313
exchangeOAuthForBackendJwt,
1414
hasBackendAccessToken,
1515
useSession,
16-
} from "@/lib/auth-client";
16+
} from "@/lib/auth/auth-client";
1717
import { getQueryClient } from "@/lib/get-query-client";
1818

1919
const TanStackDevTools =
@@ -61,7 +61,7 @@ export function Providers({ children, locale, messages }: ProvidersProps) {
6161
<QueryClientProvider client={queryClient}>
6262
<JotaiProvider>
6363
<BackendJwtBridge />
64-
<NextIntlClientProvider locale={locale} messages={messages}>
64+
<NextIntlClientProvider locale={locale} messages={messages} timeZone="Asia/Seoul">
6565
{children}
6666
</NextIntlClientProvider>
6767
</JotaiProvider>

apps/web/src/config/messages/en.json

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,5 +8,10 @@
88
"cancel": "Cancel",
99
"confirm": "Confirm",
1010
"delete": "Delete"
11-
}
11+
},
12+
"loginWelcome": "Welcome to Fullstack Starter",
13+
"loginSubtitle": "Get started with your social account",
14+
"continueWithGoogle": "Continue with Google",
15+
"continueWithFacebook": "Continue with Facebook",
16+
"continueWithGithub": "Continue with GitHub"
1217
}

apps/web/src/config/messages/ja.json

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,5 +8,10 @@
88
"cancel": "キャンセル",
99
"confirm": "確認",
1010
"delete": "削除"
11-
}
11+
},
12+
"loginWelcome": "フルスタックスターターへようこそ",
13+
"loginSubtitle": "ソーシャルアカウントで簡単に始めましょう",
14+
"continueWithGoogle": "Googleで始める",
15+
"continueWithFacebook": "Facebookで始める",
16+
"continueWithGithub": "GitHubで始める"
1217
}

apps/web/src/config/messages/ko.json

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,5 +8,10 @@
88
"cancel": "취소",
99
"confirm": "확인",
1010
"delete": "삭제"
11-
}
11+
},
12+
"loginWelcome": "풀스택 스타터에 오신 것을 환영합니다",
13+
"loginSubtitle": "소셜 계정으로 간편하게 시작하세요",
14+
"continueWithGoogle": "구글로 시작하기",
15+
"continueWithFacebook": "페이스북으로 시작하기",
16+
"continueWithGithub": "깃허브로 시작하기"
1217
}

apps/web/src/lib/api-client.ts

Lines changed: 1 addition & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,41 +1,6 @@
11
import axios from "axios";
22
import { env } from "@/config/env";
3-
4-
const STORAGE_PREFIX = "fullstack_";
5-
6-
const STORAGE_KEYS = {
7-
ACCESS_TOKEN: `${STORAGE_PREFIX}access_token`,
8-
REFRESH_TOKEN: `${STORAGE_PREFIX}refresh_token`,
9-
};
10-
11-
function getAccessToken() {
12-
if (typeof window === "undefined") return null;
13-
return localStorage.getItem(STORAGE_KEYS.ACCESS_TOKEN);
14-
}
15-
16-
function getRefreshToken() {
17-
if (typeof window === "undefined") return null;
18-
return localStorage.getItem(STORAGE_KEYS.REFRESH_TOKEN);
19-
}
20-
21-
function setAccessToken(token: string) {
22-
if (typeof window !== "undefined") {
23-
localStorage.setItem(STORAGE_KEYS.ACCESS_TOKEN, token);
24-
}
25-
}
26-
27-
function setRefreshToken(token: string) {
28-
if (typeof window !== "undefined") {
29-
localStorage.setItem(STORAGE_KEYS.REFRESH_TOKEN, token);
30-
}
31-
}
32-
33-
function clearTokens() {
34-
if (typeof window !== "undefined") {
35-
localStorage.removeItem(STORAGE_KEYS.ACCESS_TOKEN);
36-
localStorage.removeItem(STORAGE_KEYS.REFRESH_TOKEN);
37-
}
38-
}
3+
import { clearTokens, getAccessToken, getRefreshToken, setAccessToken } from "@/lib/auth/token";
394

405
export const apiClient = axios.create({
416
baseURL: env.NEXT_PUBLIC_API_URL,
@@ -124,5 +89,3 @@ apiClient.interceptors.response.use(
12489
return Promise.reject(error);
12590
}
12691
);
127-
128-
export { getAccessToken, getRefreshToken, setAccessToken, setRefreshToken, clearTokens };
Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,8 @@
22

33
import { createAuthClient } from "better-auth/react";
44
import { env } from "@/config/env";
5-
import {
6-
apiClient,
7-
clearTokens,
8-
getAccessToken,
9-
setAccessToken,
10-
setRefreshToken,
11-
} from "@/lib/api-client";
5+
import { apiClient } from "@/lib/api-client";
6+
import { clearTokens, getAccessToken, setAccessToken, setRefreshToken } from "@/lib/auth/token";
127

138
export type OAuthProviderId = "google" | "github" | "facebook";
149

apps/web/src/lib/auth/token.ts

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
const STORAGE_PREFIX = "fullstack_";
2+
3+
const STORAGE_KEYS = {
4+
ACCESS_TOKEN: `${STORAGE_PREFIX}access_token`,
5+
REFRESH_TOKEN: `${STORAGE_PREFIX}refresh_token`,
6+
};
7+
8+
export interface AuthTokens {
9+
access_token: string;
10+
refresh_token: string;
11+
}
12+
13+
export function getAccessToken(): string | null {
14+
if (typeof window === "undefined") return null;
15+
return localStorage.getItem(STORAGE_KEYS.ACCESS_TOKEN);
16+
}
17+
18+
export function getRefreshToken(): string | null {
19+
if (typeof window === "undefined") return null;
20+
return localStorage.getItem(STORAGE_KEYS.REFRESH_TOKEN);
21+
}
22+
23+
export function setAccessToken(token: string): void {
24+
if (typeof window !== "undefined") {
25+
localStorage.setItem(STORAGE_KEYS.ACCESS_TOKEN, token);
26+
}
27+
}
28+
29+
export function setRefreshToken(token: string): void {
30+
if (typeof window !== "undefined") {
31+
localStorage.setItem(STORAGE_KEYS.REFRESH_TOKEN, token);
32+
}
33+
}
34+
35+
export function setTokens(tokens: AuthTokens): void {
36+
setAccessToken(tokens.access_token);
37+
setRefreshToken(tokens.refresh_token);
38+
}
39+
40+
export function clearTokens(): void {
41+
if (typeof window !== "undefined") {
42+
localStorage.removeItem(STORAGE_KEYS.ACCESS_TOKEN);
43+
localStorage.removeItem(STORAGE_KEYS.REFRESH_TOKEN);
44+
}
45+
}
46+
47+
export function hasTokens(): boolean {
48+
return Boolean(getAccessToken()) && Boolean(getRefreshToken());
49+
}

apps/web/src/lib/i18n/request.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,5 +9,6 @@ export default getRequestConfig(async ({ requestLocale }) => {
99
return {
1010
locale,
1111
messages: (await import(`@/config/messages/${locale}.json`)).default,
12+
timeZone: "Asia/Seoul",
1213
};
1314
});

0 commit comments

Comments
 (0)