Consolidate auth/token management into tokenUtility

- Make tokenUtility.js the single source of truth for localStorage
- Add getRawToken() and isAuthenticated() to tokenUtility
- Rewrite authService.js to delegate storage to tokenUtility
- Fix calendar api.js direct localStorage access
- Remove unused setToken import from apiUtil.js
This commit is contained in:
Adam Moussa 2026-04-16 16:25:26 -04:00
parent ec8cca86d1
commit e7fb682f71
4 changed files with 84 additions and 154 deletions

View file

@ -1,5 +1,5 @@
import { API_ERROR_MESSAGE } from "./constants";
import { getAccessToken, setToken } from "./tokenUtility";
import { getAccessToken } from "./tokenUtility";
const STANDARD_HEADERS = {
Accept: "application/json",

View file

@ -1,4 +1,5 @@
import { get, post } from "../../apiUtil";
import { getAccessToken } from "../../tokenUtility";
import { API_URL } from "../../constants";
// Fetch events for calendar view (with date range)
@ -101,7 +102,7 @@ export async function deleteEvent(id) {
method: "DELETE",
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${localStorage.getItem("token")}`,
Authorization: getAccessToken(),
},
});

View file

@ -1,177 +1,88 @@
// Authentication Service
const API_BASE_URL = process.env.REACT_APP_API_URL || "http://localhost:5000";
import { getAccessToken, removeToken, getUser, isAuthenticated, getRawToken } from "../tokenUtility";
/**
* Login user with username and password
* @param {string} username - User's email/username
* @param {string} password - User's password
* @returns {Promise<Object>} - Authentication response with token and user data
*/
export async function login(username, password) {
const response = await fetch(`${API_BASE_URL}/api/Authentication/login`, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
Username: username,
Password: password,
}),
});
const API_BASE_URL = process.env.REACT_APP_API_URL || "";
if (!response.ok) {
if (response.status === 401) {
throw new Error("Invalid credentials");
}
throw new Error("Login failed");
}
export { isAuthenticated };
const data = await response.json();
return data;
}
/**
* Logout user - clear local storage
*/
export function logout() {
localStorage.removeItem("token");
localStorage.removeItem("user");
}
/**
* Check if user is authenticated
* @returns {boolean}
*/
export function isAuthenticated() {
const token = localStorage.getItem("token");
if (!token) return false;
// Check if token is expired
try {
const payload = JSON.parse(atob(token.split(".")[1]));
const expiration = new Date(payload.exp * 1000);
return expiration > new Date();
} catch (e) {
return false;
}
}
/**
* Get current user from local storage
* @returns {Object|null}
*/
export function getCurrentUser() {
const userStr = localStorage.getItem("user");
if (!userStr) return null;
try {
return JSON.parse(userStr);
} catch (e) {
return null;
}
return getUser();
}
/**
* Get authentication token
* @returns {string|null}
*/
export function getToken() {
return localStorage.getItem("token");
return getRawToken();
}
export function logout() {
removeToken();
}
/**
* Change user password
* @param {string} currentPassword - Current password
* @param {string} newPassword - New password
* @param {string} confirmPassword - Confirm new password
* @returns {Promise<Object>}
*/
export async function changePassword(currentPassword, newPassword, confirmPassword) {
const token = getToken();
const response = await fetch(`${API_BASE_URL}/api/Authentication/ChangePassword`, {
method: "POST",
headers: {
"Content-Type": "application/json",
"Authorization": `Bearer ${token}`,
},
body: JSON.stringify({
Currentpassword: currentPassword,
Newpassword: newPassword,
Confirmpassword: confirmPassword,
}),
});
const response = await fetch(`${API_BASE_URL}/api/Authentication/ChangePassword`, {
method: "POST",
headers: {
"Content-Type": "application/json",
"Authorization": getAccessToken(),
},
body: JSON.stringify({
Currentpassword: currentPassword,
Newpassword: newPassword,
Confirmpassword: confirmPassword,
}),
});
if (!response.ok) {
throw new Error("Failed to change password");
}
if (!response.ok) {
throw new Error("Failed to change password");
}
return await response.json();
return await response.json();
}
/**
* Request password reset
* @param {string} email - User's email
* @returns {Promise<Object>}
*/
export async function forgotPassword(email) {
const response = await fetch(`${API_BASE_URL}/api/Authentication/ForgetPassword?Email=${encodeURIComponent(email)}`, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
});
const response = await fetch(`${API_BASE_URL}/api/Authentication/ForgetPassword?Email=${encodeURIComponent(email)}`, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
});
if (!response.ok) {
throw new Error("Failed to send password reset email");
}
if (!response.ok) {
throw new Error("Failed to send password reset email");
}
return await response.json();
return await response.json();
}
/**
* Verify password reset code
* @param {string} code - Verification code
* @returns {Promise<Object>}
*/
export async function verifyResetCode(code) {
const response = await fetch(`${API_BASE_URL}/api/Authentication/VerificationCode?code=${encodeURIComponent(code)}`, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
});
const response = await fetch(`${API_BASE_URL}/api/Authentication/VerificationCode?code=${encodeURIComponent(code)}`, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
});
if (!response.ok) {
throw new Error("Invalid verification code");
}
if (!response.ok) {
throw new Error("Invalid verification code");
}
return await response.json();
return await response.json();
}
/**
* Reset password with code
* @param {string} email - User's email
* @param {string} code - Verification code
* @param {string} password - New password
* @returns {Promise<Object>}
*/
export async function resetPassword(email, code, password) {
const response = await fetch(`${API_BASE_URL}/api/Authentication/ResetPassword`, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
Email: email,
Code: code,
Password: password,
}),
});
const response = await fetch(`${API_BASE_URL}/api/Authentication/ResetPassword`, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
Email: email,
Code: code,
Password: password,
}),
});
if (!response.ok) {
throw new Error("Failed to reset password");
}
if (!response.ok) {
throw new Error("Failed to reset password");
}
return await response.json();
return await response.json();
}

View file

@ -18,15 +18,33 @@ export const getAccessToken = () => {
return `Bearer ${user.token}`;
}
export const getRawToken = () => {
let result = window.localStorage.getItem(tokenKey);
if (!result) {
return null;
}
return JSON.parse(result).token || null;
}
export const getUser = () => {
let result = window.localStorage.getItem(tokenKey);
if (!result) {
return {};
return null;
}
return JSON.parse(result);
}
export const removeToken = () => {
window.localStorage.removeItem(tokenKey);
}
}
export const isAuthenticated = () => {
const token = getRawToken();
if (!token) return false;
try {
const payload = JSON.parse(atob(token.split(".")[1]));
return new Date(payload.exp * 1000) > new Date();
} catch (e) {
return false;
}
}