Files
paskia/examples/restricted-api.html
T

245 lines
8.7 KiB
HTML

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Restricted API Demo</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<div class="container">
<header>
<h1>🔐 Restricted API Demo</h1>
<p class="subtitle">Demonstrates iframe-based authentication using postMessage</p>
</header>
<div class="content">
<div class="section">
<h2>Authentication Modes</h2>
<button onclick="showLoginMode()">Show Login Mode</button>
<button onclick="showReauthMode()">Show Reauth Mode</button>
<button onclick="hideIframe()">Hide Iframe</button>
</div>
<div class="section">
<h2>API Tests</h2>
<button onclick="testUserInfo()">Get User Info</button>
<button onclick="testProtectedAPI()">Test Protected API</button>
<button onclick="logout()">Logout</button>
</div>
<div id="status" class="hidden"></div>
<div class="section">
<h2>Message Events</h2>
<pre id="message-log">Waiting for messages...</pre>
</div>
</div>
</div>
<script>
let currentApiCall = null;
let iframeInitialized = false;
const messageLog = document.getElementById('message-log');
let messages = [];
window.addEventListener('message', (event) => {
const data = event.data;
if (!data?.type) return;
// Log all messages
const timestamp = new Date().toLocaleTimeString();
messages.push(`[${timestamp}] ${JSON.stringify(data, null, 2)}`);
if (messages.length > 10) messages.shift();
messageLog.textContent = messages.join('\n\n');
switch (data.type) {
case 'auth-ready':
iframeInitialized = true;
showStatus('Authentication iframe is ready', 'info');
break;
case 'auth-success':
showStatus('✓ Authentication successful!', 'success');
hideAuthIframe();
if (currentApiCall) {
setTimeout(() => {
currentApiCall();
currentApiCall = null;
}, 500);
}
break;
case 'auth-forbidden':
showStatus('⚠ You are authenticated but lack required permissions', 'error');
hideAuthIframe();
currentApiCall = null;
break;
case 'auth-logout':
showStatus('User logged out', 'info');
currentApiCall = null;
break;
case 'auth-error':
showStatus(`⚠ ${data.message || 'Authentication failed'}`, data.cancelled ? 'info' : 'error');
// Don't hide iframe on error - let user retry
break;
case 'auth-cancelled':
showStatus(`Operation cancelled: ${data.message || ''}`, 'info');
// Don't hide iframe - deprecated message type
break;
case 'auth-back':
showStatus('User clicked Back', 'info');
hideAuthIframe();
currentApiCall = null;
break;
case 'auth-close-request':
// Iframe wants to be closed (legacy)
hideAuthIframe();
break;
}
});
function showLoginMode() {
let iframe = document.getElementById('auth-iframe');
if (!iframe) {
iframe = document.createElement('iframe');
iframe.id = 'auth-iframe';
iframe.title = 'Authentication';
document.body.appendChild(iframe);
}
iframe.src = '/auth/restricted?mode=login';
showStatus('Login mode loaded - for users who are not authenticated', 'info');
}
function showReauthMode() {
let iframe = document.getElementById('auth-iframe');
if (!iframe) {
iframe = document.createElement('iframe');
iframe.id = 'auth-iframe';
iframe.title = 'Authentication';
document.body.appendChild(iframe);
}
iframe.src = '/auth/restricted?mode=reauth';
showStatus('Reauth mode loaded - for additional verification of authenticated users', 'info');
}
function showAuthIframe() {
let iframe = document.getElementById('auth-iframe');
if (!iframe) {
iframe = document.createElement('iframe');
iframe.id = 'auth-iframe';
iframe.title = 'Authentication';
iframe.src = '/auth/restricted';
document.body.appendChild(iframe);
iframeInitialized = true;
}
}
function hideIframe() {
hideAuthIframe();
showStatus('Iframe hidden', 'info');
}
function hideAuthIframe() {
const iframe = document.getElementById('auth-iframe');
if (iframe) iframe.remove();
}
async function testUserInfo() {
showStatus('Fetching user info...');
try {
const response = await fetch('/auth/api/user-info', {
method: 'POST',
credentials: 'include'
});
if (response.status === 401 || response.status === 403) {
showStatus(`⚠ Authentication required (${response.status})`);
currentApiCall = testUserInfo;
showAuthIframe();
return;
}
if (!response.ok) {
showStatus(`Error: ${response.status} ${response.statusText}`);
return;
}
const data = await response.json();
showStatus('✓ User info retrieved successfully!');
displayApiResponse('User Info', data);
} catch (error) {
showStatus(`Error: ${error.message}`);
}
}
async function testProtectedAPI() {
showStatus('Testing protected API...');
try {
const response = await fetch('/auth/api/user-info', {
method: 'POST',
credentials: 'include'
});
if (response.status === 401 || response.status === 403) {
showStatus(`⚠ Authentication required (${response.status})`);
currentApiCall = testProtectedAPI;
showAuthIframe();
return;
}
if (!response.ok) {
showStatus(`Error: ${response.status} ${response.statusText}`);
return;
}
const data = await response.json();
showStatus('✓ Protected API call successful!');
displayApiResponse('Protected Data', data);
} catch (error) {
showStatus(`Error: ${error.message}`);
}
}
async function logout() {
showStatus('Logging out...');
try {
const response = await fetch('/auth/api/logout', {
method: 'POST',
credentials: 'include'
});
if (response.ok || response.status === 401) {
showStatus('✓ Logged out successfully!');
hideAuthIframe();
currentApiCall = null;
} else {
showStatus(`Logout error: ${response.status}`);
}
} catch (error) {
showStatus(`Error: ${error.message}`);
}
}
function showStatus(message, type = 'info') {
const statusDiv = document.getElementById('status');
statusDiv.innerHTML = `<p>${message}</p>`;
statusDiv.className = `status ${type}`;
statusDiv.classList.remove('hidden');
}
function displayApiResponse(title, data) {
const statusDiv = document.getElementById('status');
statusDiv.innerHTML += `<h3>${title}</h3><pre>${JSON.stringify(data, null, 2)}</pre>`;
}
</script>
</body>
</html>