Blocking access behind email verification is the fastest way to kill activation. Users who sign up expecting to try the product and instead land on a 'check your email' dead end abandon at dramatically higher rates — and most never return. CWE-284 covers improper access control, and this is exactly that: treating unverified users as unauthorized when the threat model doesn't justify it. Every hour a new user spends waiting for a verification email is an hour your competitor keeps them active.
Medium because the failure mode is revenue loss through activation drop-off, not a direct security vulnerability — the access being blocked is the user's own account.
In src/middleware.ts, remove the redirect that blocks unverified users from the app. Let them through and surface a persistent banner instead:
// Allow unverified users into the app
if (!session.user.emailVerified) {
// Set a header or cookie the layout reads to show the banner
const response = NextResponse.next();
response.headers.set('x-email-unverified', '1');
return response;
}
Render <VerifyEmailBanner /> from src/components/VerifyEmailBanner.tsx in your root layout — dismissible, persistent, non-blocking.
ID: saas-onboarding.signup-flow.email-verification-nonblocking
Severity: medium
What to look for: Trace what happens immediately after a user submits the signup form. Enumerate all middleware checks and route guards that reference email verification status. Count the routes that are gated behind verification. Quote the actual redirect logic if found.
Pass criteria: After signup, the user lands in the application (or a welcome/onboarding screen) without being required to verify their email first. Email verification may be prompted or nudged but is not a hard block to accessing at least 80% of core functionality routes.
Fail criteria: After signup, the user is redirected to a "check your email" page with no way to access the application until they verify. Any route guard that returns 403/redirect for unverified users on pages a new user would naturally visit.
Do NOT pass when: A "soft gate" shows a full-screen modal with no dismiss button blocking the dashboard — this is functionally identical to a hard gate and is NOT a pass.
Skip (N/A) when: The application handles genuinely sensitive data where verification is a regulatory or security requirement (e.g., healthcare, financial services) — detectable if the codebase contains explicit compliance references such as HIPAA, PCI, SOC2 annotations.
Detail on fail: "Post-signup middleware redirects unverified users to /verify-email. Users cannot access the dashboard or try the product without email verification, creating unnecessary friction."
Remediation: In src/middleware.ts, allow unverified users to access the app:
// Instead of blocking unverified users:
if (!session.user.emailVerified) {
// Show banner, don't redirect
return NextResponse.next();
}
Show a persistent but dismissible banner in src/components/VerifyEmailBanner.tsx rather than a hard gate.
Cross-reference: For auth middleware patterns and session management, the Auth & Session Audit covers verification flow design in detail.