import { createKeycloakAdminClient } from '~/server/utils/keycloak-admin'; export default defineEventHandler(async (event) => { console.log('🔄 Forgot password endpoint called at:', new Date().toISOString()); try { const { email } = await readBody(event); console.log('📧 Password reset request for email:', email ? 'present' : 'missing'); // Input validation if (!email || typeof email !== 'string') { throw createError({ statusCode: 400, statusMessage: 'Email is required' }); } // Basic email validation const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; if (!emailRegex.test(email)) { throw createError({ statusCode: 400, statusMessage: 'Please enter a valid email address' }); } const config = useRuntimeConfig() as any; try { // Create Keycloak admin client const adminClient = createKeycloakAdminClient(); console.log('🔧 Using Keycloak admin client for password reset'); // Get admin token const adminToken = await adminClient.getAdminToken(); console.log('✅ Admin token obtained'); // Find user by email const users = await adminClient.findUserByEmail(email, adminToken); console.log('🔍 User search result:', { found: users.length > 0 }); if (users.length === 0) { // For security, don't reveal if email exists or not console.log('⚠️ Email not found, but returning success message for security'); return { success: true, message: 'If the email exists in our system, a reset link has been sent.' }; } const userId = users[0].id; console.log('👤 Found user:', { id: userId, email: users[0].email }); // Send password reset email await adminClient.sendPasswordResetEmail( userId, adminToken, config.keycloak.clientId, config.keycloak.callbackUrl ); console.log('✅ Password reset email sent successfully'); return { success: true, message: 'If the email exists in our system, a reset link has been sent.' }; } catch (keycloakError: any) { console.error('❌ Keycloak API error:', keycloakError); // Handle timeout errors specifically if (keycloakError.name === 'AbortError') { console.error('⏰ Password reset request timed out after 30 seconds'); return { success: true, message: 'Password reset request is being processed. If the email exists in our system, a reset link will be sent shortly.' }; } // Handle SMTP/email server errors if (keycloakError.message?.includes('send reset email') || keycloakError.message?.includes('SMTP') || keycloakError.message?.includes('500')) { console.error('📧 Email server error detected, but user search was successful'); return { success: true, message: 'If the email exists in our system, a reset link has been sent. If you don\'t receive an email, please contact your administrator.' }; } // Handle permission errors if (keycloakError.message?.includes('403') || keycloakError.message?.includes('Forbidden')) { console.error('🔒 Permission error detected - admin client may not have proper roles'); console.error('💡 Suggestion: Check that admin-cli client has view-users and manage-users roles'); return { success: true, message: 'Password reset service is temporarily unavailable. Please contact your administrator.' }; } // For security, don't reveal specific errors to the user return { success: true, message: 'If the email exists in our system, a reset link has been sent.' }; } } catch (error: any) { console.error('❌ Forgot password error:', error); // If it's already a createError, just throw it if (error.statusCode) { throw error; } // Generic error for unexpected issues throw createError({ statusCode: 500, statusMessage: 'Failed to process password reset request. Please try again.' }); } });