diff --git a/pages/auth/verify.vue b/pages/auth/verify.vue index 20fceb2..19eb600 100644 --- a/pages/auth/verify.vue +++ b/pages/auth/verify.vue @@ -173,27 +173,45 @@ const verifyEmail = async () => { // Call the API endpoint to verify the email const response = await $fetch(`/api/auth/verify-email?token=${token.value}`, { method: 'GET' - }); + }) as any; console.log('[auth/verify] Email verification successful:', response); + // Extract email from response + const email = response?.data?.email || ''; + const partialSuccess = response?.data?.partialSuccess || false; + // Redirect to success page with email info - const email = route.query.email || ''; - const redirectUrl = `/auth/verify-success${email ? `?email=${encodeURIComponent(email as string)}` : ''}`; + let redirectUrl = `/auth/verify-success`; + const queryParams = []; + + if (email) { + queryParams.push(`email=${encodeURIComponent(email)}`); + } + + if (partialSuccess) { + queryParams.push('warning=partial'); + } + + if (queryParams.length > 0) { + redirectUrl += '?' + queryParams.join('&'); + } await navigateTo(redirectUrl); } catch (err: any) { console.error('[auth/verify] Email verification failed:', err); - if (err.statusCode === 400) { - error.value = 'Invalid or expired verification token. Please request a new verification email.'; + if (err.statusCode === 410) { + error.value = 'Verification link has expired. Please request a new verification email.'; + } else if (err.statusCode === 409) { + error.value = 'This verification link has already been used or is invalid.'; + } else if (err.statusCode === 400) { + error.value = 'Invalid verification token. Please request a new verification email.'; } else if (err.statusCode === 404) { error.value = 'User not found. The verification token may be invalid.'; - } else if (err.statusCode === 409) { - error.value = 'Email is already verified. You can now log in to your account.'; } else { - error.value = err.message || 'Email verification failed. Please try again or contact support.'; + error.value = err.data?.message || err.message || 'Email verification failed. Please try again or contact support.'; } verifying.value = false; diff --git a/server/api/auth/verify-email.get.ts b/server/api/auth/verify-email.get.ts index d724da8..13b5194 100644 --- a/server/api/auth/verify-email.get.ts +++ b/server/api/auth/verify-email.get.ts @@ -18,6 +18,8 @@ export default defineEventHandler(async (event) => { // Update user verification status in Keycloak const { createKeycloakAdminClient } = await import('~/server/utils/keycloak-admin'); const keycloak = createKeycloakAdminClient(); + + let partialSuccess = false; try { await keycloak.updateUserProfile(userId, { @@ -29,27 +31,38 @@ export default defineEventHandler(async (event) => { console.log('[verify-email] Successfully verified user:', userId, 'email:', email); - // Redirect to success page - return sendRedirect(event, '/auth/verify-success?email=' + encodeURIComponent(email), 302); - } catch (keycloakError: any) { console.error('[verify-email] Keycloak update failed:', keycloakError.message); - // Even if Keycloak update fails, consider verification successful if token was valid // This prevents user frustration due to backend issues - return sendRedirect(event, '/auth/verify-success?email=' + encodeURIComponent(email) + '&warning=partial', 302); + partialSuccess = true; } + // Return JSON response for client-side navigation + return { + success: true, + data: { + userId, + email, + partialSuccess + } + }; + } catch (error: any) { console.error('[verify-email] Verification failed:', error.message); - // Handle different error types with appropriate redirects + // Return error response if (error.message?.includes('expired')) { - return sendRedirect(event, '/auth/verify-expired', 302); + throw createError({ + statusCode: 410, + statusMessage: 'Verification link has expired. Please request a new one.' + }); } else if (error.message?.includes('already used') || error.message?.includes('not found')) { - return sendRedirect(event, '/auth/verify-expired?reason=used', 302); + throw createError({ + statusCode: 409, + statusMessage: 'This verification link has already been used or is invalid.' + }); } else { - // For other errors, show a generic error page throw createError({ statusCode: 400, statusMessage: error.message || 'Invalid verification link'