Files
SweetHome/app/services/AuthService.js
Claw AI c2235cf575
All checks were successful
Build frontend / build (push) Successful in 1m26s
Fix build: syntax errors, duplicate useEffects, import paths
- Fixed broken useEffect syntax in 4 owner pages (bookings, calendar, profits, properties)
- Removed duplicate useEffect blocks
- Fixed ClientLayout import path for AuthService (../ -> ./)
2026-03-28 14:53:45 +00:00

126 lines
3.1 KiB
JavaScript

/**
* 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 AuthService = Object.freeze({
addToken(token) {
if (!token || typeof token !== 'string') return;
localStorage.setItem(TOKEN_KEY, token);
},
getToken() {
return localStorage.getItem(TOKEN_KEY);
},
deleteToken() {
localStorage.removeItem(TOKEN_KEY);
},
/**
* 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;
return {
id: payload['http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier'] || payload.sub || null,
name: payload['http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name'] || null,
email: payload['http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress'] || null,
phone: payload['http://schemas.xmlsoap.org/ws/2005/05/identity/claims/mobilephone'] || null,
roles: this.getRoles(),
};
},
/**
* 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 Admin role
* @returns {boolean}
*/
isAdmin() {
return this.getRoles().includes('Admin');
},
/**
* Authenticated user without Owner or Admin role (i.e. customer)
* @returns {boolean}
*/
isCustomer() {
return this.isAuthenticated() && !this.isOwner() && !this.isAdmin();
},
/**
* No token — guest user
* @returns {boolean}
*/
isGuest() {
return !this.getToken();
},
/**
* Token exists
* @returns {boolean}
*/
isAuthenticated() {
return !!this.getToken();
},
});
export default AuthService;