Skip to content

πŸ› Failed login shows a "success: Signed out" toast (401 interceptor triggers a global signout)Β #4305

Closed

Description

@PierreBrisorgueil

Symptom

Submitting wrong credentials on the login form surfaces a green success: Signed out snackbar instead of a login-failed error. The success/error feedback is inverted and misleading.

Root cause β€” a 3-step chain in the axios interceptors

  1. Bad credentials β†’ backend 401. signinAuthenticate returns responses.error(res, 401, 'Unauthorized', …) β€” correct.
  2. The global 401 handler fires onSignout() on the signin request's own 401. src/lib/services/axios.js:35:
    if (err.response.status === 401 && err.config && !err.config.__isRetryRequest) {
      onSignout();                       // β†’ authStore.signout(), bound in app.vue:261
      snackbar.text = 'Signin failed';
      snackbar.color = errorColor;
      snackbar.status = true;
    }
    A failed login is not a session expiry, but it is a 401, so the interceptor kicks off a full signout: signout() POSTs /signout (src/modules/auth/stores/auth.store.js:268), clears auth state, resets PostHog, refreshes nav.
  3. The side-effect /signout succeeds, and its success flows through the success snackbar interceptor. The /signout response is 200 { type:'success', message:'Signed out' }. With snackbar.methods: ["post","put"] and status:true (src/config/index.js:13-22), the success interceptor (axios.js:24-33) sets:
    snackbar.text = `${response.data.type}: ${response.data.message}`; // "success: Signed out"
    snackbar.color = successColor; // green
    This resolves after the error snackbar from step 2, so it overwrites the real error. Net visible result: a green success: Signed out toast on a failed login.

Two distinct defects

  • D1 (behavior): the global 401β†’signout interceptor should not run for the sign-in attempt itself (and arguably only when a session actually exists). Triggering a server round-trip signout + state wipe + analytics reset on every bad-password attempt is wrong.
  • D2 (feedback): even setting that aside, a programmatic signout fired as a side effect must not raise a success snackbar, and the login error must be the message the user sees.

Suggested fix (frontend only)

  • Exempt the sign-in request from the global 401 auto-signout β€” e.g. gate onSignout() on authStore.isLoggedIn (only sign out an actually-authenticated session), and/or skip the auth endpoints. A failed login should set the error snackbar and stop.
  • Make the programmatic signout() snackbar-silent (mark its /signout request so the success interceptor skips it, mirroring the existing __isRetryRequest flag) so a side-effect signout never shows success: Signed out.
  • Add a test: POST /signin β†’ 401 β‡’ snackbar is the login error (error color), onSignout() not called, no success: Signed out.

Affected files

  • src/lib/services/axios.js:24-39 (success + 401 interceptors)
  • src/modules/auth/stores/auth.store.js:258-289 (signout)
  • src/modules/app/app.vue:261 (onSignout binding)
  • src/config/index.js:13-22 (snackbar methods/status)

Created via /dev:issue

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions