Skip to content

feat(web): improve login error messages and add forgot password flow#931

Merged
AchoArnold merged 3 commits into
mainfrom
feat/improve-login-error-messages-and-forgot-password
Jun 29, 2026
Merged

feat(web): improve login error messages and add forgot password flow#931
AchoArnold merged 3 commits into
mainfrom
feat/improve-login-error-messages-and-forgot-password

Conversation

@AchoArnold

Copy link
Copy Markdown
Member

Summary

Improves the login experience by replacing raw Firebase error strings with user-friendly messages and adding a forgot password flow.

Changes

Error Message Improvements

  • Maps Firebase error codes to human-readable messages from the Firebase UI translations
  • Adds field-level error display using :error and :error-messages on v-text-field components (fields turn red with specific messages)
  • Adds client-side validation: empty/invalid email and empty password show errors before hitting Firebase

Forgot Password Flow

  • Adds a Forgot Password? link below the password field (sign-in mode only)
  • Inline form: email input + Send Reset Link button (replaces the sign-in form in the same card)
  • On success: shows a success alert + Back to Sign In button
  • On error: shows field-level errors (invalid email, user not found, too many requests)

- Map Firebase error codes to user-friendly messages from Firebase UI
  translations (e.g. 'Incorrect password' instead of raw error strings)
- Add field-level error display using :error and :error-messages on
  v-text-field components so invalid fields turn red
- Add client-side validation for empty/invalid email and empty password
- Implement inline forgot password flow with email input, reset link
  submission via sendPasswordResetEmail, and success confirmation

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@what-the-diff

what-the-diff Bot commented Jun 29, 2026

Copy link
Copy Markdown

PR Summary

  • Enhancement of User Security:
    New functionality has been added that allows users to renew their passwords. By simply filling out a form, users can request a password reset notification via email.

  • Improved Error Handling:
    Error tracking has been updated to be more detailed. Rather than monitoring only general errors, it now also includes specific error tracking for individual elements.

  • Email Validation Checks:
    We've put in place a system to ensure emails are correctly formatted before they're accepted in the login and password reset forms. This ensures the system won't be bogged down with non-existent emails.

  • Introduction of Error & Validation Methods:
    The program has been improved with new functions that offer better error handling and form management. These include distinct commands for clearing errors, validating emails, and checking the login form.

  • Revamped Template Structure:
    The user interface now provides a more seamless experience as the password reset form is only displayed when required.

  • Refined Error Display Logic:
    Finally, the way the system communicates errors to the user has been revamped. It now uses unified, clear language to relay issues to the user, improving the overall experience and making troubleshooting easier.

@codacy-production

Copy link
Copy Markdown

Up to standards ✅

🟢 Issues 0 issues

Results:
0 new issues

View in Codacy

🟢 Metrics 28 complexity · 0 duplication

Metric Results
Complexity 28
Duplication 0

View in Codacy

NEW Get contextual insights on your PRs based on Codacy's metrics, along with PR and Jira context, without leaving GitHub. Enable AI reviewer
TIP This summary will be updated as you push new changes.

@greptile-apps

greptile-apps Bot commented Jun 29, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR improves the email sign-in experience by replacing raw Firebase error strings with human-readable field-level messages and adding an inline forgot-password flow (email input \u2192 success confirmation \u2192 back to sign-in).

  • Error mapping overhaul: Firebase error codes are now routed to specific form fields (email/password) or a general alert, with client-side pre-validation preventing unnecessary round-trips.
  • Forgot password flow: A new form replaces the sign-in form in the same card when triggered, calls sendPasswordResetEmail, and shows a success banner or field-level errors on failure.
  • auth/invalid-credential targeting: The modern Firebase Auth error that covers both wrong-email and wrong-password scenarios is mapped only to the password field, which can mislead users who mistype their email address.

Confidence Score: 3/5

The auth flow change is mostly solid, but one error-code mapping actively gives users wrong information about which field caused their login failure.

The auth/invalid-credential code is returned by modern Firebase Auth for both a non-existent email and a wrong password; pinning it to a password-field message will consistently mislead users who mistype their email into looking at the wrong field. Both issues are in the core sign-in path that every email user hits.

web/app/components/FirebaseAuth.vue — specifically the handleError switch block and the Firebase call arguments in submitEmail.

Important Files Changed

Filename Overview
web/app/components/FirebaseAuth.vue Adds forgot-password flow and maps Firebase error codes to user-friendly field-level messages; auth/invalid-credential is incorrectly mapped to a password-only field error, and submitEmail passes untrimmed email to Firebase while submitPasswordReset correctly trims.

Sequence Diagram

%%{init: {'theme': 'neutral'}}%%
sequenceDiagram
    participant U as User
    participant UI as FirebaseAuth.vue
    participant FB as Firebase Auth

    U->>UI: Click Continue with email
    UI->>UI: "showEmailForm = true"

    alt Sign In / Sign Up
        U->>UI: Enter email + password, Submit
        UI->>UI: validateLoginForm()
        alt Validation fails
            UI-->>U: Field-level error
        else Validation passes
            UI->>FB: signInWithEmailAndPassword / createUserWithEmailAndPassword
            alt Success
                FB-->>UI: FirebaseUser
                UI-->>U: Navigate to /
            else Error
                FB-->>UI: FirebaseError code
                UI->>UI: handleError()
                UI-->>U: Field-level or general error
            end
        end
    end

    alt Forgot Password
        U->>UI: Click Forgot Password
        UI->>UI: "showForgotPassword = true"
        U->>UI: Enter email, Click Send Reset Link
        UI->>UI: validateEmail()
        alt Validation fails
            UI-->>U: Email field error
        else Validation passes
            UI->>FB: sendPasswordResetEmail(email.trim())
            alt Success
                FB-->>UI: void
                UI-->>U: Success alert
            else Error
                FB-->>UI: FirebaseError code
                UI->>UI: handleError()
                UI-->>U: Field-level or general error
            end
        end
        U->>UI: Click Back to Sign In
        UI->>UI: "showForgotPassword = false"
    end
Loading
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
sequenceDiagram
    participant U as User
    participant UI as FirebaseAuth.vue
    participant FB as Firebase Auth

    U->>UI: Click Continue with email
    UI->>UI: "showEmailForm = true"

    alt Sign In / Sign Up
        U->>UI: Enter email + password, Submit
        UI->>UI: validateLoginForm()
        alt Validation fails
            UI-->>U: Field-level error
        else Validation passes
            UI->>FB: signInWithEmailAndPassword / createUserWithEmailAndPassword
            alt Success
                FB-->>UI: FirebaseUser
                UI-->>U: Navigate to /
            else Error
                FB-->>UI: FirebaseError code
                UI->>UI: handleError()
                UI-->>U: Field-level or general error
            end
        end
    end

    alt Forgot Password
        U->>UI: Click Forgot Password
        UI->>UI: "showForgotPassword = true"
        U->>UI: Enter email, Click Send Reset Link
        UI->>UI: validateEmail()
        alt Validation fails
            UI-->>U: Email field error
        else Validation passes
            UI->>FB: sendPasswordResetEmail(email.trim())
            alt Success
                FB-->>UI: void
                UI-->>U: Success alert
            else Error
                FB-->>UI: FirebaseError code
                UI->>UI: handleError()
                UI-->>U: Field-level or general error
            end
        end
        U->>UI: Click Back to Sign In
        UI->>UI: "showForgotPassword = false"
    end
Loading

Comments Outside Diff (1)

  1. web/app/components/FirebaseAuth.vue, line 123-135 (link)

    P2 Email passed to Firebase without trimming in submitEmail. validateLoginForm validates email.value.trim(), so a value like " user@example.com " passes client-side validation but is forwarded to Firebase untrimmed. submitPasswordReset correctly uses email.value.trim() — the same pattern should be applied here to stay consistent.

Reviews (1): Last reviewed commit: "feat(web): improve login error messages ..." | Re-trigger Greptile

Comment on lines +204 to +207
case 'auth/wrong-password':
case 'auth/invalid-credential':
errorMessages.value.add('password', 'Incorrect password')
break

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 auth/invalid-credential misleadingly shown as a password error. Modern Firebase Auth (with email enumeration protection enabled) returns auth/invalid-credential for both a non-existent email address and a wrong password. Placing that error exclusively on the password field ("Incorrect password") tells a user who simply mistyped their email address that their password is wrong — sending them in the wrong direction. The original wording "Invalid email or password" surfaced as a general message was intentionally ambiguous for this reason.

Suggested change
case 'auth/wrong-password':
case 'auth/invalid-credential':
errorMessages.value.add('password', 'Incorrect password')
break
case 'auth/wrong-password':
errorMessages.value.add('password', 'Incorrect password')
break
case 'auth/invalid-credential':
generalError.value = 'Invalid email or password'
break

- Map auth/invalid-credential to both email and password fields since
  modern Firebase returns this code for either wrong email or password
- Trim email before passing to Firebase in submitEmail to match the
  pattern already used in submitPasswordReset

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@AchoArnold AchoArnold merged commit d4cacea into main Jun 29, 2026
8 of 10 checks passed
@AchoArnold AchoArnold deleted the feat/improve-login-error-messages-and-forgot-password branch June 29, 2026 17:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant