Authentication & Authorization
Overview
StockEase Frontend implements JWT-based authentication with role-based access control (RBAC). This directory documents the complete authentication flow, user authorization system, and session management.
Authentication & Authorization Architecture
Login API Call"] Backend["π₯οΈ Backend API
Validate Credentials"] JWT["π JWT Token
+ User Role"] Storage["πΎ localStorage
token, role, username"] ProtectedRoute["π‘οΈ Protected Routes
Check Role"] Dashboard["π Dashboard
Admin/User"] User -->|Enter credentials| LoginPage LoginPage -->|username + password| AuthService AuthService -->|POST /api/auth/login| Backend Backend -->|Verify DB| Backend Backend -->|Return JWT| JWT JWT -->|Extract token + role| Storage Storage -->|Stored in localStorage| Storage LoginPage -->|Check role| ProtectedRoute ProtectedRoute -->|Validate role| ProtectedRoute ProtectedRoute -->|Navigate to| Dashboard style User fill:#e8f5e9 style LoginPage fill:#fff3e0 style AuthService fill:#e3f2fd style Backend fill:#f3e5f5 style JWT fill:#fce4ec style Storage fill:#e0f2f1 style ProtectedRoute fill:#fff9c4 style Dashboard fill:#c8e6c9
Key Components
1.
Authentication
(src/api/auth.ts)
User login and JWT token extraction
See: Authentication Flow & Implementation
2.
Authorization (src/pages/App.tsx,
Components)
Role-based access control and route protection
See: Role-Based Access Control (RBAC)
3. Sessions & Tokens (localStorage, JWT lifecycle)
Token storage, expiration, and session management
See: Session & Token Management
Authentication Flow (Step-by-Step)
1. User Submits Credentials (Login Page)
// src/pages/LoginPage.tsx
const handleLogin = async () => {
if (!username || !password) {
setError('Fields are required');
return;
}
try {
const response = await login(username, password); // Call auth service
const { token, role } = response;
// Persist to localStorage
localStorage.setItem('token', token);
localStorage.setItem('role', role);
localStorage.setItem('username', username);
// Redirect based on role
navigate(role === 'ROLE_ADMIN' ? '/admin' : '/user');
} catch (err) {
// Handle 401, network errors, etc.
setError('Invalid credentials');
}
};2. Backend Validates Credentials
POST /api/auth/login HTTP/1.1
Content-Type: application/json
{
"username": "admin",
"password": "SecurePass123!"
}
HTTP/1.1 200 OK
Content-Type: application/json
{
"success": true,
"data": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
}
3. Frontend Decodes JWT Payload
// src/api/auth.ts
const token = response.data.data; // JWT string
const decodedPayload = JSON.parse(atob(token.split('.')[1])); // Decode payload
const role = decodedPayload.role; // Extract role: ROLE_ADMIN or ROLE_USER
return { token, role };JWT Structure:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9. β Header
eyJ1c2VyIjoiYWRtaW4iLCJyb2xlIjoiUk9MRV9BRE1JTiJ9. β Payload (decoded: {"user":"admin","role":"ROLE_ADMIN"})
SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c β Signature (verified by backend)
4. Token Stored in localStorage
localStorage.setItem('token', 'eyJhbGciOi...');
localStorage.setItem('role', 'ROLE_ADMIN');
localStorage.setItem('username', 'admin');5. Request Interceptor Attaches Token
// Every subsequent request includes Bearer token
GET /api/products HTTP/1.1
Authorization: Bearer eyJhbGciOi...
// Attached automatically by:
// src/services/apiClient.ts request interceptor6. Route Protection & Redirect
// src/pages/LoginPage.tsx useEffect
useEffect(() => {
const role = localStorage.getItem('role');
if (role) {
// Redirect to appropriate dashboard
navigate(role === 'ROLE_ADMIN' ? '/admin' : '/user', { replace: true });
}
}, [navigate]);User Roles
ROLE_ADMIN (Administrator)
Permissions:
- View admin dashboard
- Create products
- Delete products
- Edit product details
- View all inventory
Protected Routes:
/adminβ Admin dashboard/add-productβ Product creation/delete-productβ Product deletion/product/:id/editβ Edit products
ROLE_USER (Regular User)
Permissions:
- View user dashboard
- Search products
- View product details
- View stock levels (read-only)
Protected Routes:
/userβ User dashboard/search-productβ Product search/list-stockβ Stock viewing/product/:id/editβ View only (no edit)
Guest (Not Logged In)
Permissions:
- View home page
- View login page
Protected Routes:
- Cannot access any
/admin,/user,/add-product, etc.
Session Lifecycle
Timeline of a User Session
TIME EVENT STORAGE STATE
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
00:00 User navigates to /login token: null, role: null
00:05 Enters credentials token: null, role: null
00:10 Clicks "Login" token: null, role: null
00:15 Backend validates token: null, role: null
00:20 JWT returned & stored token: "eyJ...", role: "ROLE_ADMIN"
00:25 Redirected to /admin token: "eyJ...", role: "ROLE_ADMIN"
00:30 Makes API calls with token [Every request includes Bearer token]
05:00 User clicks "Logout" (logout button would clear storage)
05:05 localStorage cleared token: null, role: null
05:10 Redirected to /login token: null, role: null
05:15 Session ended User must login again
Token Expiration Handling
Current Behavior
No automatic token refresh implemented.
When token expires:
- Request sent with expired token
- Backend returns 401 Unauthorized
- Response interceptor catches 401
- Token cleared from localStorage
- User sees login page
// src/services/apiClient.ts response interceptor
if (error.response?.status === 401) {
localStorage.removeItem('token'); // Clear token
console.warn('Unauthorized access - redirecting to login');
}User Experience:
User making API call with expired token
β
Request fails with 401
β
Session cleared automatically
β
User redirected to login (or sees error)
β
Must re-authenticate
Recommended Improvement: Token Refresh
Future Implementation (not current):
// Proposed: Refresh token mechanism
const refreshToken = async () => {
try {
const response = await apiClient.post('/api/auth/refresh', {
refreshToken: localStorage.getItem('refreshToken'),
});
localStorage.setItem('token', response.data.token);
// Retry original request with new token
} catch (err) {
// Refresh failed - logout user
localStorage.clear();
navigate('/login');
}
};Password Security Requirements
StockEase enforces strong password validation:
// From src/__tests__/utils/validation-rules/auth-validation.test.ts
export const validatePassword = (password: string) => {
const errors = [];
if (password.length < 8) {
errors.push('Password must be at least 8 characters long');
}
if (!/[A-Z]/.test(password)) {
errors.push('Password must contain at least one uppercase letter');
}
if (!/[a-z]/.test(password)) {
errors.push('Password must contain at least one lowercase letter');
}
if (!/\d/.test(password)) {
errors.push('Password must contain at least one digit');
}
if (!/[!@#$%^&*()_+=[\]{};':"\\|,.<>/?]/.test(password)) {
errors.push('Password must contain at least one special character');
}
return { valid: errors.length === 0, errors };
};Requirements:
- β Minimum 8 characters
- β At least 1 uppercase letter (A-Z)
- β At least 1 lowercase letter (a-z)
- β At least 1 digit (0-9)
- β At least 1 special character (!@#$%^&*)
Example Valid Passwords:
SecurePass123!MyPassword2024#Admin@2024
Example Invalid Passwords:
password123!β No uppercasePASSWORD123!β No lowercasePassword!β No digitPassword123β No special characterPass1!β Too short (< 8 chars)
Security Best Practices
β DO
- β Always validate input (empty fields, password requirements)
- β Store token in localStorage after login
- β Attach token to all authenticated requests (via interceptor)
- β Clear token on 401 error (automatic logout)
- β Check user role before rendering protected components
- β Implement logout button to clear session
- β Use HTTPS in production (enforced)
- β Validate on both client and server
β DON'T
- β Store password in localStorage (never)
- β Send password in subsequent requests (only for login)
- β Hardcode credentials in frontend code
- β Trust client-side role validation (verify on backend)
- β Log tokens or sensitive data to console
- β Allow requests without valid token
- β Use HTTP in production (use HTTPS only)
- β Skip server-side authentication validation
Related Documentation
- Authentication Flow & Implementation β Detailed login process and JWT handling
- Role-Based Access Control (RBAC) β Route protection and permission management
- Session & Token Management β Token storage, lifecycle, and expiration
- API Communication Security β Bearer tokens and API security
- Frontend Security β XSS prevention and input validation
Quick Reference
| Aspect | Implementation | Status |
|---|---|---|
| Login | POST /api/auth/login with username/password | β Implemented |
| JWT Storage | localStorage after successful login | β Implemented |
| Token Attachment | Automatic via request interceptor | β Implemented |
| Role-Based Access | Check role before rendering routes | β Implemented |
| 401 Handling | Clear token and redirect to login | β Implemented |
| Password Requirements | 8+ chars, uppercase, lowercase, digit, special | β Implemented |
| Token Refresh | Not implemented | β³ Future |
| HttpOnly Cookies | Not implemented (using localStorage) | β οΈ Recommendation |
| Multi-Factor Auth (MFA) | Not implemented | β³ Future |
| Session Timeout | No automatic timeout | β³ Future |
Last Updated: November 13, 2025
Author: StockEase Security Team
Status: Enterprise-Grade Authentication
System