Refactor login error handling and improve user feedback
- Update LoginForm component to display error messages directly from the authentication response. - Modify useAuth composable to handle login errors more effectively, ensuring proper error messages are thrown. - Enhance login API response to return structured error messages for invalid credentials. - Adjust Cidaas utility to throw specific errors for invalid username/password scenarios.
This commit is contained in:
@@ -49,7 +49,8 @@
|
||||
"WebFetch(domain:www.shadcn-vue.com)",
|
||||
"WebFetch(domain:docs.cidaas.com)",
|
||||
"WebFetch(domain:articles.cidaas.de)",
|
||||
"WebFetch(domain:pre-release-docs.cidaas.com)"
|
||||
"WebFetch(domain:pre-release-docs.cidaas.com)",
|
||||
"mcp__playwright__browser_console_messages"
|
||||
],
|
||||
"deny": [],
|
||||
"ask": []
|
||||
|
||||
@@ -32,19 +32,14 @@ const onSubmit = handleSubmit(async (values) => {
|
||||
// Redirect happens in login() function
|
||||
} catch (error: any) {
|
||||
console.error('Login error:', error)
|
||||
submitError.value = error.data?.message || 'Anmeldung fehlgeschlagen. Bitte versuchen Sie es erneut.'
|
||||
// Error message is now directly in error.message (thrown by useAuth composable)
|
||||
submitError.value = error.message || 'Anmeldung fehlgeschlagen. Bitte versuchen Sie es erneut.'
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<form @submit="onSubmit" class="space-y-6">
|
||||
<!-- Error Alert -->
|
||||
<Alert v-if="submitError" class="border-destructive bg-destructive/10 text-white">
|
||||
<AlertCircle class="h-5 w-5 text-destructive" />
|
||||
<AlertDescription class="text-white/90">{{ submitError }}</AlertDescription>
|
||||
</Alert>
|
||||
|
||||
<!-- Email Field -->
|
||||
<FormField v-slot="{ componentField }" name="email">
|
||||
<FormItem>
|
||||
@@ -67,6 +62,12 @@ const onSubmit = handleSubmit(async (values) => {
|
||||
</FormItem>
|
||||
</FormField>
|
||||
|
||||
<!-- Error Alert -->
|
||||
<Alert v-if="submitError" class="border-destructive bg-destructive/10 text-white">
|
||||
<AlertCircle class="h-5 w-5 text-destructive" />
|
||||
<AlertDescription class="text-white/90">{{ submitError }}</AlertDescription>
|
||||
</Alert>
|
||||
|
||||
<!-- Submit Button -->
|
||||
<Button type="submit" variant="experimenta" size="experimenta" class="w-full" :disabled="isSubmitting">
|
||||
<Loader2 v-if="isSubmitting" class="mr-2 h-5 w-5 animate-spin" />
|
||||
|
||||
@@ -17,26 +17,32 @@ export function useAuth() {
|
||||
* Direct authentication via Cidaas API (no redirect)
|
||||
*/
|
||||
async function login(email: string, password: string) {
|
||||
try {
|
||||
// Call login endpoint - creates session directly
|
||||
await $fetch('/api/auth/login', {
|
||||
method: 'POST',
|
||||
body: { email, password },
|
||||
})
|
||||
// Call login endpoint - creates session directly
|
||||
const response = await $fetch<{ success: boolean; message?: string }>('/api/auth/login', {
|
||||
method: 'POST',
|
||||
body: { email, password },
|
||||
// Don't throw on 4xx/5xx, we handle the response ourselves
|
||||
ignoreResponseError: true,
|
||||
})
|
||||
|
||||
// Refresh user session
|
||||
await fetch()
|
||||
|
||||
// Redirect to homepage or saved destination
|
||||
const redirectAfterLogin = useCookie('redirect_after_login')
|
||||
const destination = redirectAfterLogin.value || '/'
|
||||
redirectAfterLogin.value = null // Clear cookie
|
||||
|
||||
navigateTo(destination)
|
||||
} catch (error) {
|
||||
console.error('Login failed:', error)
|
||||
// Check if login was successful
|
||||
if (!response.success) {
|
||||
// Throw error with the server's message (contains German text with umlauts)
|
||||
const error: any = new Error(response.message || 'Login failed')
|
||||
error.data = response
|
||||
error.statusCode = 401
|
||||
throw error
|
||||
}
|
||||
|
||||
// Refresh user session
|
||||
await fetch()
|
||||
|
||||
// Redirect to homepage or saved destination
|
||||
const redirectAfterLogin = useCookie('redirect_after_login')
|
||||
const destination = redirectAfterLogin.value || '/'
|
||||
redirectAfterLogin.value = null // Clear cookie
|
||||
|
||||
navigateTo(destination)
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
|
||||
import { z } from 'zod'
|
||||
import { eq } from 'drizzle-orm'
|
||||
import { users } from '../../database/schema'
|
||||
|
||||
const loginSchema = z.object({
|
||||
email: z.string().email('Invalid email address'),
|
||||
@@ -93,15 +94,19 @@ export default defineEventHandler(async (event) => {
|
||||
|
||||
// Handle specific error cases
|
||||
if (error.statusCode === 401) {
|
||||
throw createError({
|
||||
statusCode: 401,
|
||||
statusMessage: 'Ungültige E-Mail-Adresse oder Passwort',
|
||||
})
|
||||
// Set response status and return error as JSON body
|
||||
// This ensures umlauts are properly encoded in the response body
|
||||
setResponseStatus(event, 401, 'Invalid credentials')
|
||||
return {
|
||||
success: false,
|
||||
message: 'Ungültige E-Mail-Adresse oder Passwort',
|
||||
}
|
||||
}
|
||||
|
||||
throw createError({
|
||||
statusCode: 500,
|
||||
statusMessage: 'Anmeldung fehlgeschlagen',
|
||||
})
|
||||
setResponseStatus(event, 500, 'Login failed')
|
||||
return {
|
||||
success: false,
|
||||
message: 'Anmeldung fehlgeschlagen',
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
@@ -256,6 +256,14 @@ export async function loginWithPassword(
|
||||
console.error('Cidaas password login failed:', errorData)
|
||||
|
||||
// Handle specific errors
|
||||
// Cidaas returns 400 with error: 'invalid_username_password' for invalid credentials
|
||||
if (response.status === 400 && errorData.error === 'invalid_username_password') {
|
||||
throw createError({
|
||||
statusCode: 401,
|
||||
statusMessage: 'Invalid email or password',
|
||||
})
|
||||
}
|
||||
|
||||
if (response.status === 401) {
|
||||
throw createError({
|
||||
statusCode: 401,
|
||||
|
||||
Reference in New Issue
Block a user