Skip to content
Open
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
9 changes: 9 additions & 0 deletions src/accessToken.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
let accessToken: string | null = null;

export function getAccessToken(): string | null {
return accessToken;
}

export function setAccessToken(token: string | null): void {
accessToken = token;
}
4 changes: 4 additions & 0 deletions src/api/authApi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,10 @@ export async function refreshSession() {
return response.data;
}

export async function deleteSession() {
await axiosInstance.delete("/account/tokens");
}

export async function getCurrentUser() {
const response = await axiosInstance.get<AccountUser>("/account/me");
return response.data;
Expand Down
10 changes: 5 additions & 5 deletions src/axiosInstance.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,19 @@
import axios, { AxiosError, type InternalAxiosRequestConfig } from "axios";
import { getAccessToken, setAccessToken } from "./accessToken";

const API_BASE_URL = import.meta.env.VITE_HTB_API;

export const axiosInstance = axios.create({
baseURL: API_BASE_URL,
withCredentials: true,
headers: {
accept: "application/json",
},
});

axiosInstance.interceptors.request.use(
(config) => {
const token = localStorage.getItem("auth-token");
const token = getAccessToken();
if (token) {
config.headers.Authorization = `Bearer ${token}`;
}
Expand All @@ -31,14 +33,12 @@ let refreshRequest: Promise<string> | null = null;
async function refreshAccessToken(): Promise<string> {
if (refreshRequest) return refreshRequest;
refreshRequest = (async () => {
const token = localStorage.getItem("auth-token");
if (!token) throw new Error("No session to refresh");
const response = await axios.post<{ access_token: string }>(
`${API_BASE_URL}/account/tokens`,
undefined,
{ headers: { Authorization: `Bearer ${token}` } },
{ withCredentials: true },
);
localStorage.setItem("auth-token", response.data.access_token);
setAccessToken(response.data.access_token);
return response.data.access_token;
})().finally(() => {
refreshRequest = null;
Expand Down
20 changes: 9 additions & 11 deletions src/components/Authentication.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,13 @@ import {
useState,
createContext,
} from "react";
import { getCurrentUser, refreshSession } from "../api/authApi";
import { deleteSession, getCurrentUser, refreshSession } from "../api/authApi";
import type { AccountUser } from "../api/authApi";
import { assertStaffToken } from "../utils/authorization";
import { Center, Spinner, Text, VStack } from "@chakra-ui/react";
import { Navigate, useLocation } from "react-router-dom";
import { toast } from "react-hot-toast";
import { setAccessToken } from "../accessToken";

interface IUserContext {
login: (token: string) => Promise<AccountUser>;
Expand All @@ -37,21 +38,22 @@ export function AuthProvider({ children }: IAuthProviderProps) {
const [user, setUser] = useState<AccountUser | null>(null);

const logout = useCallback(() => {
localStorage.removeItem("auth-token");
setAccessToken(null);
setIsAuthenticated(false);
setUser(null);
void deleteSession().catch(() => undefined);
}, []);

const login = useCallback(async (token: string) => {
try {
localStorage.setItem("auth-token", token);
setAccessToken(token);
assertStaffToken(token);
const user = await getCurrentUser();
setIsAuthenticated(true);
setUser(user);
return user;
} catch (err) {
localStorage.removeItem("auth-token");
setAccessToken(null);
throw err;
}
}, []);
Expand All @@ -67,15 +69,10 @@ export function AuthProvider({ children }: IAuthProviderProps) {

useEffect(() => {
const handler = async () => {
const token = localStorage.getItem("auth-token");
if (!token) {
setLoading(false);
return;
}
try {
const tokenResponse = await refreshSession();
assertStaffToken(tokenResponse.access_token);
localStorage.setItem("auth-token", tokenResponse.access_token);
setAccessToken(tokenResponse.access_token);
const currentUser = await getCurrentUser();
setUser(currentUser);
setLoading(false);
Expand All @@ -87,8 +84,9 @@ export function AuthProvider({ children }: IAuthProviderProps) {
}
};
let timer: number;
localStorage.removeItem("auth-token");
handler().then(() => {
timer = window.setInterval(handler, 30000);
timer = window.setInterval(handler, 10 * 60 * 1000);
});

return () => {
Expand Down