Skip to content

Commit 3a8a089

Browse files
committed
Added authentication check in client
1 parent 2c62aed commit 3a8a089

File tree

1 file changed

+119
-0
lines changed

1 file changed

+119
-0
lines changed

client/src/App.jsx

Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,10 @@ function App() {
1919
const [cookies, setCookies] = useState(null);
2020
const [cookiesLoading, setCookiesLoading] = useState(true);
2121
const [cookiesError, setCookiesError] = useState(null);
22+
const [user, setUser] = useState(null);
23+
const [userLoading, setUserLoading] = useState(true);
24+
const [userError, setUserError] = useState(null);
25+
const [needsLogin, setNeedsLogin] = useState(false);
2226

2327
// Helper: decode percent-encoded cookie values safely
2428
const safeDecode = (val) => {
@@ -63,6 +67,58 @@ function App() {
6367
});
6468
}, []);
6569

70+
// Fetch user data with auth refresh logic
71+
useEffect(() => {
72+
const fetchUser = async () => {
73+
try {
74+
// Try to fetch user data
75+
const userRes = await fetch(buildApiPath("/api/user"), {
76+
credentials: "include",
77+
});
78+
79+
// If unauthorized, try to refresh the token
80+
if (userRes.status === 401) {
81+
const refreshRes = await fetch(buildApiPath("/auth/refresh"), {
82+
credentials: "include",
83+
});
84+
85+
// If refresh succeeded, retry fetching user data
86+
if (refreshRes.ok) {
87+
const retryRes = await fetch(buildApiPath("/api/user"), {
88+
credentials: "include",
89+
});
90+
91+
if (retryRes.ok) {
92+
const data = await retryRes.json();
93+
setUser(data);
94+
setUserLoading(false);
95+
return;
96+
}
97+
}
98+
99+
// If refresh failed or retry failed, user needs to login
100+
setNeedsLogin(true);
101+
setUserLoading(false);
102+
return;
103+
}
104+
105+
// If the response was ok, parse and set user data
106+
if (userRes.ok) {
107+
const data = await userRes.json();
108+
setUser(data);
109+
setUserLoading(false);
110+
} else {
111+
throw new Error("Network response was not ok");
112+
}
113+
} catch (err) {
114+
setUserError(err.message);
115+
setUserLoading(false);
116+
}
117+
};
118+
119+
fetchUser();
120+
}, []);
121+
66122
return (
67123
<>
68124
<h1>J26 Infra test and demo</h1>
@@ -149,6 +205,69 @@ function App() {
149205
</tbody>
150206
</table>
151207
)}
208+
<h2>Call /api/user</h2>
209+
{userLoading && <p>Loading...</p>}
210+
{userError && <p style={{ color: "red" }}>Error: {userError}</p>}
211+
{needsLogin && (
212+
<button
213+
type="button"
214+
onClick={() => {
215+
const currentPage = encodeURIComponent(window.location.href);
216+
window.location.href = buildApiPath(
217+
`/auth/login?redirect_uri=${currentPage}`
218+
);
219+
}}
220+
style={{
221+
padding: "10px 20px",
222+
fontSize: "16px",
223+
cursor: "pointer",
224+
backgroundColor: "#007bff",
225+
color: "white",
226+
border: "none",
227+
borderRadius: "4px",
228+
marginTop: "1em",
229+
}}
230+
>
231+
Login
232+
</button>
233+
)}
234+
{user && (
235+
<table style={{ borderCollapse: "collapse", marginTop: "1em" }}>
236+
<thead>
237+
<tr>
238+
<th style={{ border: "1px solid #ccc", padding: "8px" }}>Key</th>
239+
<th style={{ border: "1px solid #ccc", padding: "8px" }}>
240+
Value
241+
</th>
242+
</tr>
243+
</thead>
244+
<tbody>
245+
{Object.entries(user).map(([key, value]) => (
246+
<tr key={key}>
247+
<td
248+
style={{
249+
border: "1px solid #ccc",
250+
padding: "8px",
251+
fontWeight: "bold",
252+
}}
253+
>
254+
{key}
255+
</td>
256+
<td
257+
style={{
258+
border: "1px solid #ccc",
259+
padding: "8px",
260+
textAlign: "left",
261+
wordBreak: "break-all",
262+
}}
263+
>
264+
{Array.isArray(value) ? value.join(", ") : String(value)}
265+
</td>
266+
</tr>
267+
))}
268+
</tbody>
269+
</table>
270+
)}
152271
</>
153272
);
154273
}

0 commit comments

Comments
 (0)