Files
SweetHome/app/services/AuthService.js

170 lines
4.1 KiB
JavaScript
Raw Normal View History

import Cookies from "js-cookie";
/**
* AuthService
* Manages authentication tokens and user role detection via JWT decoding.
*
* Roles (from JWT claims):
* - Owner: roles array contains "Owner"
* - Customer: authenticated but no "Owner" role
* - Guest: no token
*
* Methods:
* addToken(token) store JWT token
* getToken() retrieve JWT token
* deleteToken() remove JWT token
* decodeToken() decode JWT payload
* getUser() get decoded user info
* getRoles() get roles array from JWT
* isOwner() check if user has Owner role
* isCustomer() check if user is authenticated but not Owner
* isGuest() check if no token exists
* isAuthenticated() check if token exists
*/
const TOKEN_KEY = "auth_token";
const USER_KEY = "cached_user";
const AuthService = Object.freeze({
addToken(token) {
if (!token || typeof token !== "string") return;
Cookies.set(TOKEN_KEY, token, {
expires: 7,
secure: true,
sameSite: "lax",
path: "/",
});
},
getToken() {
if (typeof window === "undefined") return null;
return Cookies.get(TOKEN_KEY);
},
deleteToken() {
localStorage.removeItem(USER_KEY);
Cookies.remove(TOKEN_KEY);
},
/**
* Cache full user profile (from API)
* @param {object} user { name, email, phone, ... }
*/
cacheUser(user) {
if (!user) return;
localStorage.setItem(USER_KEY, JSON.stringify(user));
},
/**
* Get cached user profile
* @returns {object|null}
*/
getCachedUser() {
try {
return JSON.parse(localStorage.getItem(USER_KEY));
} catch {
return null;
}
},
/**
* Decode JWT payload (base64)
* @returns {object|null}
*/
decodeToken() {
const token = this.getToken();
if (!token) return null;
try {
const payload = token.split(".")[1];
return JSON.parse(atob(payload));
} catch {
return null;
}
},
/**
* Extract user info from JWT
* @returns {object|null} { id, name, email, phone, roles }
*/
getUser() {
const payload = this.decodeToken();
if (!payload) return null;
const cached = this.getCachedUser();
return {
id: payload["http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier"] || payload.sub || null,
name: cached?.name || payload["http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name"] || null,
email: cached?.email || payload["http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress"] || null,
phone: cached?.phone || payload["http://schemas.xmlsoap.org/ws/2005/05/identity/claims/mobilephone"] || null,
roles: this.getRoles(),
};
},
2026-04-17 14:40:47 +03:00
/**
* Get current authenticated user id
* @returns {number|string|null}
*/
getUserId() {
const user = this.getUser();
if (!user?.id) return null;
const parsedId = Number(user.id);
return Number.isFinite(parsedId) ? parsedId : user.id;
},
/**
* Get roles array from JWT
* @returns {string[]}
*/
getRoles() {
const payload = this.decodeToken();
if (!payload) return [];
const roles = payload["http://schemas.microsoft.com/ws/2008/06/identity/claims/role"];
if (Array.isArray(roles)) return roles;
if (typeof roles === "string") return [roles];
return [];
},
/**
* User has Owner role
* @returns {boolean}
*/
isOwner() {
return this.getRoles().includes("Owner");
},
/**
* User has RealEstateAgent role
* @returns {boolean}
*/
isAgent() {
return this.getRoles().includes("RealEstateAgent");
},
/**
2026-06-10 19:50:49 +03:00
* Authenticated user without Owner role (i.e. customer)
* @returns {boolean}
*/
isCustomer() {
return this.isAuthenticated() && !this.isOwner() && !this.isAgent();
},
/**
* No token guest user
* @returns {boolean}
*/
isGuest() {
return !this.getToken();
},
/**
* Token exists
* @returns {boolean}
*/
isAuthenticated() {
return !!this.getToken();
},
});
export default AuthService;