Skip to content

Commit

Permalink
Merge pull request #434 from M2K3K5/automatic-user-oauth
Browse files Browse the repository at this point in the history
feature: automatic OAuth login and session expiration check with redirect to login page
  • Loading branch information
Yooooomi authored Nov 24, 2024
2 parents f9f14f5 + 6210932 commit 7ce4064
Show file tree
Hide file tree
Showing 6 changed files with 87 additions and 5 deletions.
35 changes: 34 additions & 1 deletion apps/client/src/scenes/Account/Login/Login.tsx
Original file line number Diff line number Diff line change
@@ -1,21 +1,39 @@
import { useEffect } from "react";
import { useCallback, useEffect, useState } from "react";
import { useSelector } from "react-redux";
import { useNavigate } from "react-router-dom";
import { Checkbox } from "@mui/material";
import clsx from "clsx";
import Text from "../../../components/Text";
import { selectUser } from "../../../services/redux/modules/user/selector";
import { getSpotifyLogUrl } from "../../../services/tools";
import s from "../index.module.css";
import { LocalStorage, REMEMBER_ME_KEY } from "../../../services/storage";

export default function Login() {
const navigate = useNavigate();
const user = useSelector(selectUser);
const [rememberMe, setRememberMe] = useState(
LocalStorage.get(REMEMBER_ME_KEY) === "true",
);

useEffect(() => {
if (user) {
navigate("/");
} else if (LocalStorage.get(REMEMBER_ME_KEY) === "true") {
window.location.href = getSpotifyLogUrl();
}
}, [navigate, user]);

const handleRememberMeClick = useCallback(async () => {
const newRememberMe = !rememberMe;
setRememberMe(newRememberMe);
if (newRememberMe) {
LocalStorage.set(REMEMBER_ME_KEY, "true");
} else {
LocalStorage.delete(REMEMBER_ME_KEY);
}
}, [rememberMe]);

return (
<div className={s.root}>
<Text element="h1" className={s.title}>
Expand All @@ -29,6 +47,21 @@ export default function Login() {
Login
</a>
</div>
<div>
<button
type="button"
className={clsx("no-button", s.rememberMe)}
onClick={handleRememberMeClick}>
<Checkbox
checked={rememberMe}
disableRipple
disableTouchRipple
disableFocusRipple
classes={{ root: s.check }}
/>
<Text>Remember me</Text>
</button>
</div>
</div>
);
}
14 changes: 13 additions & 1 deletion apps/client/src/scenes/Account/index.module.css
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,18 @@
color: white;
height: 40px;
border-radius: 20px;
padding: 0px 24px;
padding: 0px 58px;
font-weight: bold;
}

.rememberMe {
margin-top: 8px;
cursor: pointer;
display: flex;
align-items: center;
gap: 4px;
}

.check {
padding: 0px !important;
}
6 changes: 4 additions & 2 deletions apps/client/src/scenes/Logout/Logout.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import { CircularProgress } from "@mui/material";
import React, { useEffect } from "react";
import { useEffect } from "react";
import { useNavigate } from "react-router-dom";
import Text from "../../components/Text";
import { api } from "../../services/apis/api";
import { logout } from "../../services/redux/modules/user/reducer";
import { useAppDispatch } from "../../services/redux/tools";
import { LocalStorage, REMEMBER_ME_KEY } from "../../services/storage";

export default function Logout() {
const navigate = useNavigate();
Expand All @@ -18,9 +19,10 @@ export default function Logout() {
} catch (e) {
console.error(e);
}
LocalStorage.delete(REMEMBER_ME_KEY);
navigate("/login");
}
dologout();
dologout().catch(console.error);
}, [navigate, dispatch]);

return (
Expand Down
11 changes: 11 additions & 0 deletions apps/client/src/services/apis/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,17 @@ const axios = Axios.create({
withCredentials: true,
});

// Add a response interceptor
axios.interceptors.response.use(
response => response,
error => {
if (error.response && error.response.status === 401) {
window.location.pathname = "/login";
}
return Promise.reject(error);
}
);

// Adds latency to requests without having to use chrome latency
// const get = <T>(url: string, params: Record<string, any> = {}): Promise<{ data: T }> =>
// new Promise((res, rej) => {
Expand Down
19 changes: 19 additions & 0 deletions apps/client/src/services/storage.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
interface KeyValueStorage {
get(key: string): string | undefined;
set(key: string, value: string): void;
delete(key: string): void;
}

export const LocalStorage: KeyValueStorage = {
get(key: string) {
return localStorage.getItem(key) ?? undefined;
},
set(key: string, value: string) {
localStorage.setItem(key, value);
},
delete(key: string) {
localStorage.removeItem(key);
},
};

export const REMEMBER_ME_KEY = "remember-me";
7 changes: 6 additions & 1 deletion apps/server/src/tools/middleware.ts
Original file line number Diff line number Diff line change
Expand Up @@ -133,10 +133,15 @@ export const optionalLogged = async (
export const admin = (req: Request, res: Response, next: NextFunction) => {
const { user } = req as LoggedRequest;

if (!user || !user.admin) {
if (!user) {
res.status(401).end();
return;
}

if (!user.admin) {
res.status(403).end();
return;
}
next();
};

Expand Down

0 comments on commit 7ce4064

Please sign in to comment.