Some checks failed
CI/CD — Build & Deploy / Build & Deploy (push) Failing after 25s
- Frontend: PKCE flow (oauth.js, api.js centralized, cookie-based AuthContext) - Backend: token introspection, cookies httpOnly, refresh endpoint - Replaced localStorage JWT with httpOnly session cookies - useSaveSync migrated to cookie auth - cookie-parser added - Gitea CI workflow (vps-runner pattern)
80 lines
1.8 KiB
JavaScript
Executable File
80 lines
1.8 KiB
JavaScript
Executable File
import React, { createContext, useContext, useState, useMemo, useEffect } from "react";
|
|
import PropTypes from "prop-types";
|
|
import { apiFetch } from "../lib/api";
|
|
|
|
const AuthContext = createContext();
|
|
|
|
const AuthProvider = ({ children }) => {
|
|
const [user, setUser] = useState(null);
|
|
const [loading, setLoading] = useState(true);
|
|
|
|
const refresh = async () => {
|
|
try {
|
|
const data = await apiFetch("/auth/me");
|
|
setUser(data);
|
|
} catch {
|
|
setUser(null);
|
|
}
|
|
};
|
|
|
|
useEffect(() => {
|
|
refresh().finally(() => setLoading(false));
|
|
}, []);
|
|
|
|
useEffect(() => {
|
|
const onExpired = () => setUser(null);
|
|
window.addEventListener("auth:expired", onExpired);
|
|
return () => window.removeEventListener("auth:expired", onExpired);
|
|
}, []);
|
|
|
|
const logout = async () => {
|
|
try {
|
|
await apiFetch("/auth/logout", { method: "POST" });
|
|
} catch {
|
|
// ignore
|
|
}
|
|
setUser(null);
|
|
};
|
|
|
|
const editUser = async (updatedFields) => {
|
|
const data = await apiFetch(`/users/${user.id}`, {
|
|
method: "PUT",
|
|
body: JSON.stringify(updatedFields),
|
|
});
|
|
setUser((prev) => ({ ...prev, ...data.user }));
|
|
return "User updated successfully";
|
|
};
|
|
|
|
const authContextValue = useMemo(
|
|
() => ({
|
|
user,
|
|
loading,
|
|
logout,
|
|
refresh,
|
|
editUser,
|
|
setUser: (newUser) => setUser(newUser),
|
|
}),
|
|
[user, loading]
|
|
);
|
|
|
|
return (
|
|
<AuthContext.Provider value={authContextValue}>
|
|
{children}
|
|
</AuthContext.Provider>
|
|
);
|
|
};
|
|
|
|
AuthProvider.propTypes = {
|
|
children: PropTypes.node.isRequired,
|
|
};
|
|
|
|
const useAuth = () => {
|
|
const context = useContext(AuthContext);
|
|
if (!context) {
|
|
throw new Error("useAuth must be used within an AuthProvider");
|
|
}
|
|
return context;
|
|
};
|
|
|
|
export { AuthProvider, useAuth };
|