diff --git a/public/admin/dashboard.html b/public/admin/dashboard.html
index f8d4256..9fdd6af 100644
--- a/public/admin/dashboard.html
+++ b/public/admin/dashboard.html
@@ -452,6 +452,35 @@
Quick Actions
})();
});
+ // Validate token and initialize dashboard
+ async function validateAndInit() {
+ const token = localStorage.getItem('spiralsafe_admin_token') ||
+ sessionStorage.getItem('spiralsafe_admin_token');
+
+ try {
+ const response = await fetch(`${API_BASE}/admin/auth/me`, {
+ method: 'GET',
+ headers: {
+ 'Authorization': `Bearer ${token}`,
+ 'Accept': 'application/json'
+ }
+ });
+
+ if (!response.ok) {
+ // Invalid or expired token, clear it and redirect to login
+ logout();
+ return;
+ }
+
+ // Token is valid - initialize charts and load metrics
+ initCharts();
+ loadMetrics();
+ } catch (error) {
+ // On network or other errors, clear token and redirect to login
+ logout();
+ }
+ }
+
// Logout function
function logout() {
localStorage.removeItem('spiralsafe_admin_token');
diff --git a/public/admin/login.html b/public/admin/login.html
index da0c994..3812fa7 100644
--- a/public/admin/login.html
+++ b/public/admin/login.html
@@ -308,6 +308,9 @@ 🔐 ATOM-AUTH: Conversational Cohe
if (response.ok && data.token) {
// Store token
+ // SECURITY NOTE: Storing tokens in localStorage/sessionStorage exposes them to XSS attacks.
+ // For production deployments, consider using httpOnly cookies set by the backend
+ // or implementing additional security measures (strict CSP, token rotation, etc.)
if (remember) {
localStorage.setItem('spiralsafe_admin_token', data.token);
} else {
diff --git a/public/api/index.html b/public/api/index.html
index 182efa4..e9425e0 100644
--- a/public/api/index.html
+++ b/public/api/index.html
@@ -605,10 +605,24 @@ RapiDoc
responseEl.classList.remove('hidden');
codeEl.textContent = 'Loading...';
- const response = await fetch(`${API_BASE}/api/health`);
- const data = await response.json();
+ // Demo mode: simulated response for interactive preview
+ // For production API calls, include X-API-Key header in your request
+ const simulatedResponse = {
+ status: "healthy",
+ timestamp: new Date().toISOString(),
+ version: "1.0.0",
+ services: {
+ database: "operational",
+ cache: "operational",
+ queue: "operational"
+ },
+ _note: "Interactive demo - use curl or your preferred HTTP client with a valid X-API-Key header for actual results"
+ };
- codeEl.textContent = JSON.stringify(data, null, 2);
+ // Simulate network delay
+ await new Promise(resolve => setTimeout(resolve, 500));
+
+ codeEl.textContent = JSON.stringify(simulatedResponse, null, 2);
hljs.highlightElement(codeEl);
} catch (error) {
codeEl.textContent = JSON.stringify({ error: error.message }, null, 2);