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:www.shadcn-vue.com)",
|
||||||
"WebFetch(domain:docs.cidaas.com)",
|
"WebFetch(domain:docs.cidaas.com)",
|
||||||
"WebFetch(domain:articles.cidaas.de)",
|
"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": [],
|
"deny": [],
|
||||||
"ask": []
|
"ask": []
|
||||||
|
|||||||
@@ -32,19 +32,14 @@ const onSubmit = handleSubmit(async (values) => {
|
|||||||
// Redirect happens in login() function
|
// Redirect happens in login() function
|
||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
console.error('Login error:', error)
|
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>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<form @submit="onSubmit" class="space-y-6">
|
<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 -->
|
<!-- Email Field -->
|
||||||
<FormField v-slot="{ componentField }" name="email">
|
<FormField v-slot="{ componentField }" name="email">
|
||||||
<FormItem>
|
<FormItem>
|
||||||
@@ -67,6 +62,12 @@ const onSubmit = handleSubmit(async (values) => {
|
|||||||
</FormItem>
|
</FormItem>
|
||||||
</FormField>
|
</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 -->
|
<!-- Submit Button -->
|
||||||
<Button type="submit" variant="experimenta" size="experimenta" class="w-full" :disabled="isSubmitting">
|
<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" />
|
<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)
|
* Direct authentication via Cidaas API (no redirect)
|
||||||
*/
|
*/
|
||||||
async function login(email: string, password: string) {
|
async function login(email: string, password: string) {
|
||||||
try {
|
// Call login endpoint - creates session directly
|
||||||
// Call login endpoint - creates session directly
|
const response = await $fetch<{ success: boolean; message?: string }>('/api/auth/login', {
|
||||||
await $fetch('/api/auth/login', {
|
method: 'POST',
|
||||||
method: 'POST',
|
body: { email, password },
|
||||||
body: { email, password },
|
// Don't throw on 4xx/5xx, we handle the response ourselves
|
||||||
})
|
ignoreResponseError: true,
|
||||||
|
})
|
||||||
|
|
||||||
// Refresh user session
|
// Check if login was successful
|
||||||
await fetch()
|
if (!response.success) {
|
||||||
|
// Throw error with the server's message (contains German text with umlauts)
|
||||||
// Redirect to homepage or saved destination
|
const error: any = new Error(response.message || 'Login failed')
|
||||||
const redirectAfterLogin = useCookie('redirect_after_login')
|
error.data = response
|
||||||
const destination = redirectAfterLogin.value || '/'
|
error.statusCode = 401
|
||||||
redirectAfterLogin.value = null // Clear cookie
|
|
||||||
|
|
||||||
navigateTo(destination)
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Login failed:', error)
|
|
||||||
throw error
|
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 { z } from 'zod'
|
||||||
import { eq } from 'drizzle-orm'
|
import { eq } from 'drizzle-orm'
|
||||||
|
import { users } from '../../database/schema'
|
||||||
|
|
||||||
const loginSchema = z.object({
|
const loginSchema = z.object({
|
||||||
email: z.string().email('Invalid email address'),
|
email: z.string().email('Invalid email address'),
|
||||||
@@ -93,15 +94,19 @@ export default defineEventHandler(async (event) => {
|
|||||||
|
|
||||||
// Handle specific error cases
|
// Handle specific error cases
|
||||||
if (error.statusCode === 401) {
|
if (error.statusCode === 401) {
|
||||||
throw createError({
|
// Set response status and return error as JSON body
|
||||||
statusCode: 401,
|
// This ensures umlauts are properly encoded in the response body
|
||||||
statusMessage: 'Ungültige E-Mail-Adresse oder Passwort',
|
setResponseStatus(event, 401, 'Invalid credentials')
|
||||||
})
|
return {
|
||||||
|
success: false,
|
||||||
|
message: 'Ungültige E-Mail-Adresse oder Passwort',
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
throw createError({
|
setResponseStatus(event, 500, 'Login failed')
|
||||||
statusCode: 500,
|
return {
|
||||||
statusMessage: 'Anmeldung fehlgeschlagen',
|
success: false,
|
||||||
})
|
message: 'Anmeldung fehlgeschlagen',
|
||||||
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -256,6 +256,14 @@ export async function loginWithPassword(
|
|||||||
console.error('Cidaas password login failed:', errorData)
|
console.error('Cidaas password login failed:', errorData)
|
||||||
|
|
||||||
// Handle specific errors
|
// 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) {
|
if (response.status === 401) {
|
||||||
throw createError({
|
throw createError({
|
||||||
statusCode: 401,
|
statusCode: 401,
|
||||||
|
|||||||
Reference in New Issue
Block a user