Account Verification

Verification gates a logged-in user out of the app until they confirm one or more channels, email and phone out of the box. The whole flow keys off flags the API returns on the user, so the front end never decides who needs to verify or which channels apply.

The interrupt

A router interceptor runs after the auth guard. If the user's is_verification_required flag is set and the target route is gated (any non guest-only route), it redirects to the verify screen. The reverse also holds, a user whose flag has cleared but who lands on the verify route is sent back to the landing page, which covers refreshes and stale deep links.

Because it reads the generic is_verification_required flag rather than any per-channel state, the interceptor stays the same no matter how many channels are in play.

Channels

The user carries a verification_required array listing the channels still outstanding, in order. The active channel is simply the first entry, resolved through a small useVerifyChannel composable so the view and the form read the same value.

Verification runs one channel at a time. Confirming a channel refetches the user, which drops that channel off the array, so the resolved channel advances to the next one on its own. The heading and note on the verify screen are keyed off the current channel, and the phone note pulls the last two digits from the user's phone for the "ending in XX" hint.

The verify flow

A code is sent whenever the active channel resolves or advances, driven by a watcher rather than a mount hook, since the component is reused across the redirect bounce rather than remounted. That send is silent, a throttle response never surfaces on its own.

Submitting posts the code plus the channel, then refetches the user. The redirect decision reads the refreshed is_verification_required flag. Still set means another channel is pending and the screen stays put while the channel advances. Cleared means all channels are done and the user is pushed to the landing page. Refetching before the redirect matters, otherwise the interceptor would bounce the user back on a stale flag.

Grace period

Alongside the required flags the API can return is_verification_pending and a verification_pending array. These represent channels a user is allowed to defer, letting them into the app early while still owing a verification. The interrupt does not act on pending, it only gates on required. Pending is surfaced later as a reminder banner rather than a hard block.

Dynamic register phone

Whether registration collects a phone number is driven by the system settings verification_required array. When it includes phone, the register form adds a phone field and a matching validation rule, and the value flows through to the register call. When it does not, the field and rule are absent entirely rather than hidden, so nothing empty is submitted.

The condition is resolved once in the register form composable and returned as a flag the component uses for its v-if, keeping the settings check in one place.

See also

Authentication for the auth guard and boot check this builds on. Settings for the system config that drives the register phone field.

© Websanova 2026 About Privacy