Backend: add refresh JWT (30d, token_type claim), POST /auth/refresh endpoint (rotates token pair), remember_me on login, JWT_REFRESH_EXPIRY_DAYS env var. Extractors now reject refresh tokens on protected routes. Frontend: sessionStorage for non-remembered sessions, localStorage + refresh token for remembered sessions. Transparent 401 recovery in api.ts (retry once after refresh). Remember me checkbox on login page with security note when checked.
68 lines
1.8 KiB
TypeScript
68 lines
1.8 KiB
TypeScript
"use client";
|
|
|
|
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
|
|
import { useRouter } from "next/navigation";
|
|
import { api } from "@/lib/api";
|
|
import { useAuthContext } from "@/context/auth-context";
|
|
|
|
export function useCurrentUser() {
|
|
const { token } = useAuthContext();
|
|
return useQuery({
|
|
queryKey: ["me"],
|
|
queryFn: () => api.auth.me(token!),
|
|
enabled: !!token,
|
|
retry: false,
|
|
});
|
|
}
|
|
|
|
export function useLogin() {
|
|
const { setTokens } = useAuthContext();
|
|
const router = useRouter();
|
|
const queryClient = useQueryClient();
|
|
return useMutation({
|
|
mutationFn: ({
|
|
email,
|
|
password,
|
|
rememberMe,
|
|
}: {
|
|
email: string;
|
|
password: string;
|
|
rememberMe: boolean;
|
|
}) => api.auth.login(email, password, rememberMe),
|
|
onSuccess: (data, { rememberMe }) => {
|
|
setTokens(data.access_token, data.refresh_token ?? null, rememberMe);
|
|
queryClient.invalidateQueries({ queryKey: ["me"] });
|
|
router.push("/dashboard");
|
|
},
|
|
});
|
|
}
|
|
|
|
export function useRegister() {
|
|
const { setTokens } = useAuthContext();
|
|
const router = useRouter();
|
|
const queryClient = useQueryClient();
|
|
return useMutation({
|
|
mutationFn: ({ email, password }: { email: string; password: string }) =>
|
|
api.auth.register(email, password),
|
|
onSuccess: (data) => {
|
|
setTokens(data.access_token, null, false);
|
|
queryClient.invalidateQueries({ queryKey: ["me"] });
|
|
router.push("/dashboard");
|
|
},
|
|
});
|
|
}
|
|
|
|
export function useLogout() {
|
|
const { token, setTokens } = useAuthContext();
|
|
const router = useRouter();
|
|
const queryClient = useQueryClient();
|
|
return useMutation({
|
|
mutationFn: () => (token ? api.auth.logout(token) : Promise.resolve()),
|
|
onSettled: () => {
|
|
setTokens(null, null, false);
|
|
queryClient.clear();
|
|
router.push("/login");
|
|
},
|
|
});
|
|
}
|