refactor: centralize authentication handling

- Replaced direct localStorage token access with a centralized `getBearerToken` function across various components and hooks to improve code maintainability and security.
- Updated API calls to use `authenticatedFetch` for consistent authentication handling.
- Enhanced user experience by ensuring proper redirection to login when authentication fails.
- Cleaned up unused imports and improved overall code structure for better readability.
This commit is contained in:
DESKTOP-RTLN3BA\$punk 2025-12-02 01:24:09 -08:00
parent 6cc9e38e1d
commit b2a97b39ce
35 changed files with 396 additions and 497 deletions

View file

@ -2,6 +2,7 @@
import { useCallback, useEffect, useMemo, useState } from "react";
import { toast } from "sonner";
import { authenticatedFetch, getBearerToken, handleUnauthorized } from "@/lib/auth-utils";
// ============ Types ============
@ -105,22 +106,11 @@ export function useMembers(searchSpaceId: number) {
try {
setLoading(true);
const response = await fetch(
const response = await authenticatedFetch(
`${process.env.NEXT_PUBLIC_FASTAPI_BACKEND_URL}/api/v1/searchspaces/${searchSpaceId}/members`,
{
headers: {
Authorization: `Bearer ${localStorage.getItem("surfsense_bearer_token")}`,
},
method: "GET",
}
{ method: "GET" }
);
if (response.status === 401) {
localStorage.removeItem("surfsense_bearer_token");
window.location.href = "/";
throw new Error("Unauthorized");
}
if (!response.ok) {
const errorData = await response.json().catch(() => ({}));
throw new Error(errorData.detail || "Failed to fetch members");
@ -145,13 +135,10 @@ export function useMembers(searchSpaceId: number) {
const updateMemberRole = useCallback(
async (membershipId: number, roleId: number | null) => {
try {
const response = await fetch(
const response = await authenticatedFetch(
`${process.env.NEXT_PUBLIC_FASTAPI_BACKEND_URL}/api/v1/searchspaces/${searchSpaceId}/members/${membershipId}`,
{
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${localStorage.getItem("surfsense_bearer_token")}`,
},
headers: { "Content-Type": "application/json" },
method: "PUT",
body: JSON.stringify({ role_id: roleId }),
}
@ -177,14 +164,9 @@ export function useMembers(searchSpaceId: number) {
const removeMember = useCallback(
async (membershipId: number) => {
try {
const response = await fetch(
const response = await authenticatedFetch(
`${process.env.NEXT_PUBLIC_FASTAPI_BACKEND_URL}/api/v1/searchspaces/${searchSpaceId}/members/${membershipId}`,
{
headers: {
Authorization: `Bearer ${localStorage.getItem("surfsense_bearer_token")}`,
},
method: "DELETE",
}
{ method: "DELETE" }
);
if (!response.ok) {
@ -205,14 +187,9 @@ export function useMembers(searchSpaceId: number) {
const leaveSearchSpace = useCallback(async () => {
try {
const response = await fetch(
const response = await authenticatedFetch(
`${process.env.NEXT_PUBLIC_FASTAPI_BACKEND_URL}/api/v1/searchspaces/${searchSpaceId}/members/me`,
{
headers: {
Authorization: `Bearer ${localStorage.getItem("surfsense_bearer_token")}`,
},
method: "DELETE",
}
{ method: "DELETE" }
);
if (!response.ok) {
@ -251,22 +228,11 @@ export function useRoles(searchSpaceId: number) {
try {
setLoading(true);
const response = await fetch(
const response = await authenticatedFetch(
`${process.env.NEXT_PUBLIC_FASTAPI_BACKEND_URL}/api/v1/searchspaces/${searchSpaceId}/roles`,
{
headers: {
Authorization: `Bearer ${localStorage.getItem("surfsense_bearer_token")}`,
},
method: "GET",
}
{ method: "GET" }
);
if (response.status === 401) {
localStorage.removeItem("surfsense_bearer_token");
window.location.href = "/";
throw new Error("Unauthorized");
}
if (!response.ok) {
const errorData = await response.json().catch(() => ({}));
throw new Error(errorData.detail || "Failed to fetch roles");
@ -291,13 +257,10 @@ export function useRoles(searchSpaceId: number) {
const createRole = useCallback(
async (roleData: RoleCreate) => {
try {
const response = await fetch(
const response = await authenticatedFetch(
`${process.env.NEXT_PUBLIC_FASTAPI_BACKEND_URL}/api/v1/searchspaces/${searchSpaceId}/roles`,
{
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${localStorage.getItem("surfsense_bearer_token")}`,
},
headers: { "Content-Type": "application/json" },
method: "POST",
body: JSON.stringify(roleData),
}
@ -323,13 +286,10 @@ export function useRoles(searchSpaceId: number) {
const updateRole = useCallback(
async (roleId: number, roleData: RoleUpdate) => {
try {
const response = await fetch(
const response = await authenticatedFetch(
`${process.env.NEXT_PUBLIC_FASTAPI_BACKEND_URL}/api/v1/searchspaces/${searchSpaceId}/roles/${roleId}`,
{
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${localStorage.getItem("surfsense_bearer_token")}`,
},
headers: { "Content-Type": "application/json" },
method: "PUT",
body: JSON.stringify(roleData),
}
@ -355,14 +315,9 @@ export function useRoles(searchSpaceId: number) {
const deleteRole = useCallback(
async (roleId: number) => {
try {
const response = await fetch(
const response = await authenticatedFetch(
`${process.env.NEXT_PUBLIC_FASTAPI_BACKEND_URL}/api/v1/searchspaces/${searchSpaceId}/roles/${roleId}`,
{
headers: {
Authorization: `Bearer ${localStorage.getItem("surfsense_bearer_token")}`,
},
method: "DELETE",
}
{ method: "DELETE" }
);
if (!response.ok) {
@ -404,22 +359,11 @@ export function useInvites(searchSpaceId: number) {
try {
setLoading(true);
const response = await fetch(
const response = await authenticatedFetch(
`${process.env.NEXT_PUBLIC_FASTAPI_BACKEND_URL}/api/v1/searchspaces/${searchSpaceId}/invites`,
{
headers: {
Authorization: `Bearer ${localStorage.getItem("surfsense_bearer_token")}`,
},
method: "GET",
}
{ method: "GET" }
);
if (response.status === 401) {
localStorage.removeItem("surfsense_bearer_token");
window.location.href = "/";
throw new Error("Unauthorized");
}
if (!response.ok) {
const errorData = await response.json().catch(() => ({}));
throw new Error(errorData.detail || "Failed to fetch invites");
@ -444,13 +388,10 @@ export function useInvites(searchSpaceId: number) {
const createInvite = useCallback(
async (inviteData: InviteCreate) => {
try {
const response = await fetch(
const response = await authenticatedFetch(
`${process.env.NEXT_PUBLIC_FASTAPI_BACKEND_URL}/api/v1/searchspaces/${searchSpaceId}/invites`,
{
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${localStorage.getItem("surfsense_bearer_token")}`,
},
headers: { "Content-Type": "application/json" },
method: "POST",
body: JSON.stringify(inviteData),
}
@ -476,13 +417,10 @@ export function useInvites(searchSpaceId: number) {
const updateInvite = useCallback(
async (inviteId: number, inviteData: InviteUpdate) => {
try {
const response = await fetch(
const response = await authenticatedFetch(
`${process.env.NEXT_PUBLIC_FASTAPI_BACKEND_URL}/api/v1/searchspaces/${searchSpaceId}/invites/${inviteId}`,
{
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${localStorage.getItem("surfsense_bearer_token")}`,
},
headers: { "Content-Type": "application/json" },
method: "PUT",
body: JSON.stringify(inviteData),
}
@ -508,14 +446,9 @@ export function useInvites(searchSpaceId: number) {
const revokeInvite = useCallback(
async (inviteId: number) => {
try {
const response = await fetch(
const response = await authenticatedFetch(
`${process.env.NEXT_PUBLIC_FASTAPI_BACKEND_URL}/api/v1/searchspaces/${searchSpaceId}/invites/${inviteId}`,
{
headers: {
Authorization: `Bearer ${localStorage.getItem("surfsense_bearer_token")}`,
},
method: "DELETE",
}
{ method: "DELETE" }
);
if (!response.ok) {
@ -555,14 +488,9 @@ export function usePermissions() {
const fetchPermissions = useCallback(async () => {
try {
setLoading(true);
const response = await fetch(
const response = await authenticatedFetch(
`${process.env.NEXT_PUBLIC_FASTAPI_BACKEND_URL}/api/v1/permissions`,
{
headers: {
Authorization: `Bearer ${localStorage.getItem("surfsense_bearer_token")}`,
},
method: "GET",
}
{ method: "GET" }
);
if (!response.ok) {
@ -619,22 +547,11 @@ export function useUserAccess(searchSpaceId: number) {
try {
setLoading(true);
const response = await fetch(
const response = await authenticatedFetch(
`${process.env.NEXT_PUBLIC_FASTAPI_BACKEND_URL}/api/v1/searchspaces/${searchSpaceId}/my-access`,
{
headers: {
Authorization: `Bearer ${localStorage.getItem("surfsense_bearer_token")}`,
},
method: "GET",
}
{ method: "GET" }
);
if (response.status === 401) {
localStorage.removeItem("surfsense_bearer_token");
window.location.href = "/";
throw new Error("Unauthorized");
}
if (!response.ok) {
const errorData = await response.json().catch(() => ({}));
throw new Error(errorData.detail || "Failed to fetch access info");
@ -737,13 +654,10 @@ export function useInviteInfo(inviteCode: string | null) {
}
try {
const response = await fetch(
const response = await authenticatedFetch(
`${process.env.NEXT_PUBLIC_FASTAPI_BACKEND_URL}/api/v1/invites/accept`,
{
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${localStorage.getItem("surfsense_bearer_token")}`,
},
headers: { "Content-Type": "application/json" },
method: "POST",
body: JSON.stringify({ invite_code: inviteCode }),
}