Skip to content

fix(auth): signup auth-watcher races validate() → skips email-verification gate when orgs disabled / config null #4437

Description

@PierreBrisorgueil

What — On a signup that requires email verification, the user can be dropped straight into the app WITHOUT ever seeing the "check your inbox" step — when organizations are disabled, or when the server-config fetch returned null.

Why — The email-verification step is a deliberate gate. Skipping it lets an unverified user into the app, and no router guard enforces email-verified downstream, so nothing catches it.

Scopesrc/modules/auth/views/signup.view.vue's watch.auth (~lines 260-269) calls pushAfterAuth()router.push(config.sign.route) as soon as the store sets this.auth = true (done synchronously inside the signup() action). That pre-flush watcher job flushes on an EARLIER microtask than validate()'s await authStore.signup() continuation, so the watcher runs while signupStep is still 'form' — BEFORE validate() reaches if (result.emailVerificationRequired) { signupStep = 'emailVerification'; return; }.

On the !serverConfig?.organizations?.enabled path (which is also true when serverConfig === null after a failed fetchServerConfig()), the watcher therefore navigates into the app and the verification gate is defeated. app.router.js's beforeEach has org / plan / ability gates but no emailVerified check, so nothing bounces the unverified user back.

Dormant when organizations are enabled and the config loads cleanly; deterministic on organizations-disabled deployments with email verification, and reachable anywhere fetchServerConfig() transiently returns null. Also untested — the signup view unit test mocks a static { auth: false } store, so the watcher never fires and the "shows email verification step" case is green while masking the interplay.

Fix: gate the watcher's navigation on the result classification — e.g. have signup() not flip auth (or set a separate pendingEmailVerification flag) when emailVerificationRequired, or set a synchronous submitting flag at the top of validate() and guard the watcher with it, so the emailVerification step is never skipped. validate() already calls pushAfterAuth() in every terminal branch, so the watcher's fast-path push may simply be redundant for the email/password flow (OAuth uses full-page href redirects handled by created()). Add a unit test that flips the store's real auth to exercise the race.

Refs: signup.view.vue watch.auth + validate(); auth.store.js signup().
Created via /dev:issue

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions