feat: Complete frontend-backend integration with JWT authentication
Implemented full JWT-based authentication integration between frontend and backend:
Frontend Changes:
- Updated login.html to store JWT tokens in localStorage after successful login
- Updated setup.html to use correct API payload format (master_password)
- Modified app.js and queue.js to include Bearer tokens in all authenticated requests
- Updated makeAuthenticatedRequest() to add Authorization header with JWT token
- Enhanced checkAuthentication() to verify token and redirect on 401 responses
- Updated logout() to clear tokens from localStorage
API Endpoint Updates:
- Mapped queue API endpoints to new backend structure
- /api/queue/clear → /api/queue/completed (DELETE) for clearing completed
- /api/queue/remove → /api/queue/{item_id} (DELETE) for single removal
- /api/queue/retry payload changed to {item_ids: []} array format
- /api/download/pause|resume|cancel → /api/queue/pause|resume|stop
Testing:
- Created test_frontend_integration_smoke.py with JWT token validation tests
- Verified login returns access_token, token_type, and expires_at
- Tested Bearer token authentication on protected endpoints
- Smoke tests passing for authentication flow
Documentation:
- Updated infrastructure.md with JWT authentication implementation details
- Documented token storage, API endpoint changes, and response formats
- Marked Frontend Integration task as completed in instructions.md
- Added frontend integration testing section
WebSocket:
- Verified WebSocket integration with new backend (already functional)
- Dual event handlers support both old and new message types
- Room-based subscriptions working correctly
This completes Task 7: Frontend Integration from the development instructions.
This commit is contained in:
@@ -323,13 +323,19 @@
|
||||
|
||||
const data = await response.json();
|
||||
|
||||
if (data.status === 'success') {
|
||||
showMessage(data.message, 'success');
|
||||
if (response.ok && data.access_token) {
|
||||
// Store JWT token in localStorage
|
||||
localStorage.setItem('access_token', data.access_token);
|
||||
if (data.expires_at) {
|
||||
localStorage.setItem('token_expires_at', data.expires_at);
|
||||
}
|
||||
showMessage('Login successful', 'success');
|
||||
setTimeout(() => {
|
||||
window.location.href = '/';
|
||||
}, 1000);
|
||||
} else {
|
||||
showMessage(data.message, 'error');
|
||||
const errorMessage = data.detail || data.message || 'Invalid credentials';
|
||||
showMessage(errorMessage, 'error');
|
||||
passwordInput.value = '';
|
||||
passwordInput.focus();
|
||||
}
|
||||
|
||||
@@ -503,22 +503,20 @@
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
password,
|
||||
directory
|
||||
master_password: password
|
||||
})
|
||||
});
|
||||
|
||||
const data = await response.json();
|
||||
|
||||
if (data.status === 'success') {
|
||||
showMessage('Setup completed successfully! Redirecting...', 'success');
|
||||
if (response.ok && data.status === 'ok') {
|
||||
showMessage('Setup completed successfully! Redirecting to login...', 'success');
|
||||
setTimeout(() => {
|
||||
// Use redirect_url from API response, fallback to /login
|
||||
const redirectUrl = data.redirect_url || '/login';
|
||||
window.location.href = redirectUrl;
|
||||
window.location.href = '/login';
|
||||
}, 2000);
|
||||
} else {
|
||||
showMessage(data.message, 'error');
|
||||
const errorMessage = data.detail || data.message || 'Setup failed';
|
||||
showMessage(errorMessage, 'error');
|
||||
}
|
||||
} catch (error) {
|
||||
showMessage('Setup failed. Please try again.', 'error');
|
||||
|
||||
Reference in New Issue
Block a user