14 KiB
User Authentication UI Adaptations
Overview
This document describes the necessary UI changes and adaptations required to implement the magic link-based user authentication process described in doc_userauth_process_concept.md.
Last Updated: Based on codebase analysis of current frontend implementation.
Current Frontend State
Existing Pages
-
frontend_agents/public/login.html- Contains login form with username/password fields
- Has buttons for Microsoft and Google authentication
- Has registration link
- Missing: Password reset button
-
frontend_agents/public/register.html- Contains registration form with:
- Username field
- Password field (required)
- Confirm password field (required)
- Email field
- Full name field
- Language selector
- Needs modification: Remove password fields, add email-only registration
- Contains registration form with:
-
frontend_agents/public/js/security/auth.js- Contains
setupRegisterPage()function - Contains
validateRegistrationForm()function that requires password - Contains email validation logic
- Needs modification: Remove password validation, add shared email validation function
- Contains
-
frontend_agents/public/js/shared/apiCalls.js- Contains
register()function that sends password - Missing: Password reset request and reset password API calls
- Contains
Required UI Changes
1. Login Page (frontend_agents/public/login.html)
Changes Required:
- Add "Password Reset" button/link below the login form
- Button should link to
/password-reset-request.html - Style should match existing button styles (use
btnclass with appropriate variant)
Implementation:
<!-- Add after login form, before register-options div -->
<div class="password-reset-link">
<a href="password-reset-request.html" class="btn btn-link">
<i class="fas fa-key"></i> Passwort zurücksetzen
</a>
</div>
Styling Considerations:
- Use existing CSS classes from
htmlparts/styles.css - Match styling with registration link
- Ensure responsive design matches login page layout
2. Registration Page (frontend_agents/public/register.html)
Changes Required:
- Remove password and confirm password fields
- Keep username, email, fullName, language fields
- Update form validation to not require password
- Update success message to indicate email will be sent
- Add spam folder reminder message
Implementation:
<!-- Remove these fields: -->
<!-- <div class="login-form-group">
<label for="password">Passwort*</label>
<input type="password" id="password" name="password" required minlength="8">
<div class="field-error"></div>
</div>
<div class="login-form-group">
<label for="confirm-password">Passwort bestätigen*</label>
<input type="password" id="confirm-password" name="confirm-password" required>
<div class="field-error"></div>
</div> -->
<!-- Add info message after form: -->
<div class="registration-info">
<p>Nach der Registrierung erhalten Sie eine E-Mail mit einem Link zum Setzen Ihres Passworts.</p>
<p class="spam-reminder">Bitte prüfen Sie auch Ihren Spam-Ordner, falls Sie keine E-Mail erhalten.</p>
</div>
JavaScript Changes (frontend_agents/public/js/security/auth.js):
- Update
validateRegistrationForm()to remove password validation - Update
setupRegisterPage()to handle no-password registration - Create shared
validateEmailFormat()function for reuse
3. New Page: Password Reset Request (frontend_agents/public/password-reset-request.html)
Purpose:
Allow users to request a password reset by entering their email address.
Structure:
- Similar layout to
register.html - Single email input field
- Submit button
- Link back to login page
- Success/error message area
Implementation:
<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>PowerOn - Passwort zurücksetzen</title>
<link rel="stylesheet" href="./htmlparts/styles_variables.css">
<link rel="stylesheet" href="./htmlparts/styles_base.css">
<link rel="stylesheet" href="./htmlparts/styles.css">
<link rel="stylesheet" href="./htmlparts/styles_icons.css">
</head>
<body>
<div class="login-container">
<h1>Passwort zurücksetzen</h1>
<div id="reset-request-error" class="login-error-message"></div>
<form id="password-reset-request-form">
<div class="login-form-group">
<label for="email">E-Mail-Adresse*</label>
<input type="email" id="email" name="email" required autocomplete="email">
<div class="field-error"></div>
</div>
<button type="submit" class="btn btn-success login-btn">Reset-Link anfordern</button>
</form>
<div class="register-link">
<p>Zurück zum <a href="login.html">Login</a></p>
</div>
</div>
<!-- Benötigte globale Utilities -->
<script type="module" src="js/shared/utils.js"></script>
<!-- Module -->
<script type="module" src="js/security/passwordResetRequest.js"></script>
</body>
</html>
JavaScript Module (frontend_agents/public/js/security/passwordResetRequest.js):
- Handle form submission
- Validate email format using shared function from
auth.js - Call password reset request API
- Show generic success message
- Redirect to login page after showing message
4. New Page: Password Reset (frontend_agents/public/reset.html)
Purpose:
Allow users to set a new password using the token from the magic link.
Structure:
- Similar layout to
register.html - Password field (with strength indicator)
- Confirm password field
- Submit button
- Extract token from URL parameter (
?token=<UUID>) - Success/error message area
Implementation:
<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>PowerOn - Neues Passwort setzen</title>
<link rel="stylesheet" href="./htmlparts/styles_variables.css">
<link rel="stylesheet" href="./htmlparts/styles_base.css">
<link rel="stylesheet" href="./htmlparts/styles.css">
<link rel="stylesheet" href="./htmlparts/styles_icons.css">
</head>
<body>
<div class="login-container">
<h1>Neues Passwort setzen</h1>
<div id="reset-error" class="login-error-message"></div>
<form id="reset-password-form">
<div class="login-form-group">
<label for="password">Neues Passwort*</label>
<input type="password" id="password" name="password" required minlength="8">
<div class="field-error"></div>
<small class="password-hint">Mindestens 8 Zeichen</small>
</div>
<div class="login-form-group">
<label for="confirm-password">Passwort bestätigen*</label>
<input type="password" id="confirm-password" name="confirm-password" required>
<div class="field-error"></div>
</div>
<button type="submit" class="btn btn-success login-btn">Passwort setzen</button>
</form>
<div class="register-link">
<p>Zurück zum <a href="login.html">Login</a></p>
</div>
</div>
<!-- Benötigte globale Utilities -->
<script type="module" src="js/shared/utils.js"></script>
<!-- Module -->
<script type="module" src="js/security/reset.js"></script>
</body>
</html>
JavaScript Module (frontend_agents/public/js/security/reset.js):
- Extract token from URL parameter
- Validate token format (UUID)
- Handle form submission
- Validate password strength (min 8 chars, match requirements from config)
- Validate password confirmation matches
- Call password reset API
- Show success message with spam folder reminder
- Redirect to login page after 3 seconds
5. API Calls (frontend_agents/public/js/shared/apiCalls.js)
New Functions Required:
-
requestPasswordReset(email)requestPasswordReset: async function(email) { try { return await privateApi.post('/api/local/password-reset-request', { email }); } catch (error) { ui.log.error('Password reset request error:', error); throw error; } } -
resetPassword(token, password)resetPassword: async function(token, password) { try { return await privateApi.post('/api/local/password-reset', { token, password }); } catch (error) { ui.log.error('Password reset error:', error); throw error; } } -
Update
register()function- Remove password from request body
- Update to handle new registration flow (no password required)
6. Shared Email Validation (frontend_agents/public/js/security/auth.js)
New Function:
/**
* Validates email format
* @param {string} email - Email address to validate
* @returns {boolean} - True if valid, false otherwise
*/
export function validateEmailFormat(email) {
if (!email) return false;
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
return emailRegex.test(email.trim());
}
Usage:
- Used by registration form
- Used by password reset request form
- Ensures consistent email validation across the application
UI/UX Considerations
Error Handling
-
Registration Errors:
- Username already exists → Show error on username field
- Email already exists → Show generic success (security: don't reveal email exists)
- Email sending fails → Show generic success (don't reveal email issues)
-
Password Reset Request Errors:
- Invalid email format → Show error on email field
- Email not found → Show generic success (security: don't reveal email doesn't exist)
- Rate limiting → Show error message
-
Password Reset Errors:
- Invalid/expired token → Show error message, link back to password reset request
- Password too weak → Show specific requirements
- Password mismatch → Show error on confirm password field
Success Messages
-
Registration Success:
"Registrierung erfolgreich! Bitte prüfen Sie Ihre E-Mail, um Ihr Passwort zu setzen. Falls Sie keine E-Mail erhalten, prüfen Sie bitte auch Ihren Spam-Ordner." -
Password Reset Request Success:
"Falls ein Konto mit dieser E-Mail-Adresse existiert, wurde ein Reset-Link gesendet. Bitte prüfen Sie Ihre E-Mail und auch Ihren Spam-Ordner." -
Password Reset Success:
"Passwort erfolgreich gesetzt! Sie werden zum Login weitergeleitet..."
Accessibility
- All form fields should have proper labels
- Error messages should be associated with form fields using ARIA attributes
- Success messages should be announced to screen readers
- Form validation should provide clear, actionable feedback
Responsive Design
- All pages should work on mobile devices
- Form layouts should adapt to smaller screens
- Buttons should be appropriately sized for touch interfaces
- Error messages should be readable on all screen sizes
Testing Checklist
Registration Flow
- User can register without password
- Email validation works correctly
- Success message displays correctly
- Redirect to login works
- Error handling for duplicate username
- Error handling for duplicate email (should show generic success)
Password Reset Request Flow
- User can access password reset request page from login
- Email validation works correctly
- Success message displays correctly
- Redirect to login works
- Error handling for invalid email format
- Error handling for rate limiting
Password Reset Flow
- User can access reset page with valid token
- Token extraction from URL works
- Password validation works correctly
- Password confirmation validation works
- Success message displays correctly
- Redirect to login works after 3 seconds
- Error handling for invalid token
- Error handling for expired token
- Error handling for weak password
Integration Testing
- End-to-end registration flow works
- End-to-end password reset flow works
- Email links work correctly
- Token expiration handling works
- Multiple reset requests invalidate old tokens
Implementation Order
-
Backend Changes First (prerequisites):
- Add resetToken fields to UserInDB model
- Implement password reset endpoints
- Implement email sending functionality
-
Frontend API Layer:
- Add password reset API calls to
apiCalls.js - Update registration API call
- Add password reset API calls to
-
Frontend Pages:
- Create
password-reset-request.html - Create
reset.html - Update
login.html(add reset button) - Update
register.html(remove password fields)
- Create
-
Frontend JavaScript:
- Create
passwordResetRequest.js - Create
reset.js - Update
auth.js(remove password validation, add email validation function) - Update
register.jsif needed
- Create
-
Testing:
- Test each flow independently
- Test integration between frontend and backend
- Test error scenarios
- Test edge cases
Notes
- All text should be in German to match existing UI (
login.htmluses German) - CSS classes should match existing patterns from
htmlparts/styles.css - Form validation should use existing patterns from
auth.js - Error handling should use existing patterns from
auth.js(showFieldError, clearFieldError) - Success messages should use existing patterns (showSuccessMessage)
- API calls should use existing patterns from
apiCalls.js(privateApi.post, handleResponse)