Skip to content

Commit 4883088

Browse files
author
pengyu
committed
change JWT from local storage to session storage
1 parent d666365 commit 4883088

File tree

5 files changed

+43
-51
lines changed

5 files changed

+43
-51
lines changed

frontend/src/app/hooks/useAuth.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ export const useAuth = () => {
4545
);
4646

4747
const validateToken = async () => {
48-
const token = localStorage.getItem(LocalStore.accessToken);
48+
const token = sessionStorage.getItem(LocalStore.accessToken);
4949
if (!token) {
5050
setIsAuthenticated(false);
5151
setUser(null);
@@ -85,7 +85,7 @@ export const useAuth = () => {
8585
});
8686

8787
if (data?.login.accessToken) {
88-
localStorage.setItem(LocalStore.accessToken, data.login.accessToken);
88+
sessionStorage.setItem(LocalStore.accessToken, data.login.accessToken);
8989
setIsAuthenticated(true);
9090
await refetchUser();
9191
toast.success('Login successful');
@@ -125,7 +125,7 @@ export const useAuth = () => {
125125
};
126126

127127
const handleLogout = () => {
128-
localStorage.removeItem(LocalStore.accessToken);
128+
sessionStorage.removeItem(LocalStore.accessToken);
129129
localStorage.removeItem('user');
130130
setIsAuthenticated(false);
131131
setUser(null);
Lines changed: 29 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,37 +1,48 @@
1+
// auth-context.tsx
12
"use client";
23

3-
import { useState, useEffect, useRef } from "react";
4+
import React, { createContext, useContext, useEffect, useRef, useState } from "react";
45
import { useLazyQuery } from "@apollo/client";
56
import { CHECK_TOKEN_QUERY } from "@/graphql/request";
6-
import { LocalStore } from "@/lib/storage";
77
import { LoadingPage } from "@/components/global-loading";
88

9-
interface AuthProviderProps {
10-
children: React.ReactNode;
9+
interface AuthContextValue {
10+
isAuthorized: boolean;
11+
isChecking: boolean;
12+
setIsAuthorized: React.Dispatch<React.SetStateAction<boolean>>;
1113
}
1214

13-
export const AuthProvider = ({ children }: AuthProviderProps) => {
15+
const AuthContext = createContext<AuthContextValue>({
16+
isAuthorized: false,
17+
isChecking: false,
18+
setIsAuthorized: () => {},
19+
});
20+
21+
export const useAuthContext = () => useContext(AuthContext);
22+
23+
export function AuthProvider({ children }: { children: React.ReactNode }) {
1424
const [isAuthorized, setIsAuthorized] = useState(false);
1525
const [isChecking, setIsChecking] = useState(true);
16-
const [showSignInModal, setShowSignInModal] = useState(false);
1726

1827
const [checkToken] = useLazyQuery(CHECK_TOKEN_QUERY);
19-
const timeoutRef = useRef<NodeJS.Timeout>();
28+
const timeoutRef = useRef<NodeJS.Timeout | null>(null);
2029

2130
useEffect(() => {
2231
let isMounted = true;
2332

2433
async function validateToken() {
2534
setIsChecking(true);
2635

27-
const token = localStorage.getItem(LocalStore.accessToken);
36+
// If you want to store the token in sessionStorage, do:
37+
// const token = sessionStorage.getItem("accessToken");
38+
// Otherwise, if you still prefer localStorage:
39+
const token = sessionStorage.getItem("accessToken");
40+
2841
if (!token) {
29-
// No token => not authorized, but don't block the page
42+
// No token => user is not authorized
3043
if (isMounted) {
3144
setIsAuthorized(false);
3245
setIsChecking(false);
33-
// Optionally show sign-in modal:
34-
setShowSignInModal(true);
3546
}
3647
return;
3748
}
@@ -40,20 +51,18 @@ export const AuthProvider = ({ children }: AuthProviderProps) => {
4051
timeoutRef.current = setTimeout(() => {
4152
if (isMounted) {
4253
console.error("Token validation timeout");
43-
localStorage.removeItem(LocalStore.accessToken);
54+
sessionStorage.removeItem("accessToken");
4455
setIsAuthorized(false);
4556
setIsChecking(false);
46-
setShowSignInModal(true);
4757
}
4858
}, 5000);
4959

5060
try {
5161
const { data } = await checkToken({ variables: { input: { token } } });
5262
if (isMounted) {
5363
if (!data?.checkToken) {
54-
localStorage.removeItem(LocalStore.accessToken);
64+
sessionStorage.removeItem("accessToken");
5565
setIsAuthorized(false);
56-
setShowSignInModal(true);
5766
} else {
5867
console.log("Token valid");
5968
setIsAuthorized(true);
@@ -62,9 +71,8 @@ export const AuthProvider = ({ children }: AuthProviderProps) => {
6271
} catch (error) {
6372
if (isMounted) {
6473
console.error("Token validation error:", error);
65-
localStorage.removeItem(LocalStore.accessToken);
74+
sessionStorage.removeItem("accessToken");
6675
setIsAuthorized(false);
67-
setShowSignInModal(true);
6876
}
6977
} finally {
7078
if (timeoutRef.current) {
@@ -86,16 +94,14 @@ export const AuthProvider = ({ children }: AuthProviderProps) => {
8694
};
8795
}, [checkToken]);
8896

97+
// While checking token, show loading screen
8998
if (isChecking) {
9099
return <LoadingPage />;
91100
}
92101

93-
// Always render main page, authorized or not
94102
return (
95-
<>
103+
<AuthContext.Provider value={{ isAuthorized, isChecking, setIsAuthorized }}>
96104
{children}
97-
{/* Show sign-in modal if unauthorized */}
98-
{/* <SignInModal isOpen={showSignInModal} onClose={() => setShowSignInModal(false)} /> */}
99-
</>
105+
</AuthContext.Provider>
100106
);
101-
};
107+
}

frontend/src/components/SignInModal.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ export function SignInModal({
3333
const [loginUser, { loading }] = useMutation(LOGIN_USER, {
3434
onCompleted: (data) => {
3535
if (data?.login) {
36-
localStorage.setItem('accessToken', data.login.accessToken);
36+
sessionStorage.setItem('accessToken', data.login.accessToken);
3737
localStorage.setItem('refreshToken', data.login.refreshToken);
3838
toast.success('Login successful!');
3939
setErrorMessage(null); // Clear error on success

frontend/src/contexts/AuthContext.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,13 +30,13 @@ export const AuthProvider = ({ children }: { children: React.ReactNode }) => {
3030

3131
const login = (accessToken: string, refreshToken: string) => {
3232
setToken(accessToken);
33-
localStorage.setItem("accessToken", accessToken);
33+
sessionStorage.setItem("accessToken", accessToken);
3434
localStorage.setItem("refreshToken", refreshToken);
3535
};
3636

3737
const logout = () => {
3838
setToken(null);
39-
localStorage.removeItem("accessToken");
39+
sessionStorage.removeItem("accessToken");
4040
localStorage.removeItem("refreshToken");
4141
};
4242

@@ -49,7 +49,7 @@ export const AuthProvider = ({ children }: { children: React.ReactNode }) => {
4949

5050
if (data?.refreshToken) {
5151
setToken(data.refreshToken.accessToken);
52-
localStorage.setItem("accessToken", data.refreshToken.accessToken);
52+
sessionStorage.setItem("accessToken", data.refreshToken.accessToken);
5353
return data.refreshToken.accessToken;
5454
} else {
5555
logout();

frontend/src/lib/client.ts

Lines changed: 7 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ const authLink = setContext((_, { headers }) => {
2222
if (typeof window === "undefined") {
2323
return { headers };
2424
}
25-
const accessToken = localStorage.getItem("accessToken");
25+
const accessToken = sessionStorage.getItem("accessToken");
2626
const refreshToken = localStorage.getItem("refreshToken");
2727
return {
2828
headers: {
@@ -56,21 +56,7 @@ const requestLoggingMiddleware = new ApolloLink((operation, forward) => {
5656
});
5757
});
5858

59-
// 5. Auth Middleware (reads tokens from localStorage for each request)
60-
const authMiddleware = new ApolloLink((operation, forward) => {
61-
if (typeof window === "undefined") {
62-
return forward(operation);
63-
}
64-
const token = localStorage.getItem(LocalStore.accessToken);
65-
if (token) {
66-
operation.setContext({
67-
headers: {
68-
Authorization: `Bearer ${token}`,
69-
},
70-
});
71-
}
72-
return forward(operation);
73-
});
59+
7460

7561
// 6. Define the Refresh Token Mutation (as a string or gql tag)
7662
const REFRESH_TOKEN_MUTATION = gql`
@@ -107,8 +93,8 @@ const errorLink = onError(({ graphQLErrors, networkError, operation, forward })
10793
if (!data || !data.refreshToken) {
10894
throw new Error("Refresh token failed");
10995
}
110-
// Update localStorage with new tokens
111-
localStorage.setItem("accessToken", data.refreshToken.accessToken);
96+
97+
sessionStorage.setItem("accessToken", data.refreshToken.accessToken);
11298
localStorage.setItem("refreshToken", data.refreshToken.refreshToken);
11399

114100
// Update the original operation's headers
@@ -129,7 +115,7 @@ const errorLink = onError(({ graphQLErrors, networkError, operation, forward })
129115
.catch((err) => {
130116
console.error("Refresh token error:", err);
131117
// Clear tokens, redirect or show sign-in modal
132-
localStorage.removeItem("accessToken");
118+
sessionStorage.removeItem("accessToken");
133119
localStorage.removeItem("refreshToken");
134120
window.location.href = "/login"; // or open a modal
135121
reject(err);
@@ -156,9 +142,9 @@ const splitLink = wsLink
156142
);
157143
},
158144
wsLink,
159-
from([errorLink, requestLoggingMiddleware, authMiddleware, authLink, httpLink])
145+
from([errorLink, requestLoggingMiddleware, authLink, httpLink])
160146
)
161-
: from([errorLink, requestLoggingMiddleware, authMiddleware, authLink, httpLink]);
147+
: from([errorLink, requestLoggingMiddleware, authLink, httpLink]);
162148

163149
// 9. Create the Unified Apollo Client
164150
export const client = new ApolloClient({

0 commit comments

Comments
 (0)