Improve error handling, automatically renew access token

This commit is contained in:
2025-11-06 20:47:08 +02:00
parent bb3900d23b
commit 65794be998
7 changed files with 374 additions and 175 deletions

View File

@@ -1,5 +1,16 @@
import { createContext, useContext, useEffect, useState } from "react";
import { jwtDecode } from "jwt-decode";
import { API } from "~/api/api";
export function getApiErrorMessage(error: any): string {
if (error && Array.isArray(error.errors) && error.errors.length > 0) {
return error.errors.map((e: any) => e.description).join('\n');
}
if (error && error.detail) {
return error.detail;
}
return "An unexpected error occurred.";
}
export interface User {
id: string;
@@ -14,6 +25,7 @@ interface AuthContextType {
isLoading: boolean;
login: (accessToken: string, refreshToken: string) => void;
logout: () => void;
renewSession: () => Promise<User | null>;
}
const AuthContext = createContext<AuthContextType>({
@@ -21,6 +33,7 @@ const AuthContext = createContext<AuthContextType>({
isLoading: true,
login: () => {},
logout: () => {},
renewSession: async () => null,
});
export function AuthProvider({ children }: { children: React.ReactNode }) {
@@ -80,8 +93,33 @@ export function AuthProvider({ children }: { children: React.ReactNode }) {
localStorage.removeItem("refreshToken");
};
const renewSession = async (): Promise<User | null> => {
const stored = localStorage.getItem("user");
if (!stored) {
logout();
return null;
}
const currentUser: User = JSON.parse(stored);
try {
const res = await API.renewToken(currentUser.refreshToken);
if (!res.ok) {
logout();
return null;
}
const { accessToken, refreshToken: newRefreshToken } = await res.json();
login(accessToken, newRefreshToken);
// We need to get the user object that login creates
const newStored = localStorage.getItem("user");
return newStored ? JSON.parse(newStored) : null;
} catch (error) {
logout();
return null;
}
};
return (
<AuthContext.Provider value={{ user, isLoading, login, logout }}>
<AuthContext.Provider value={{ user, isLoading, login, logout, renewSession }}>
{children}
</AuthContext.Provider>
);