Login forms without loading indicators let users click submit repeatedly while the first request is still in flight, triggering duplicate authentication attempts that can corrupt session state, burn through brute-force lockout counters, double-charge billing events on post-login redirects, and produce inconsistent MFA challenges. Missing error feedback forces users to guess why authentication failed, driving them to password managers that may paste stale credentials and accelerating account lockouts tracked under OWASP A07 (Identification & Authentication Failures). Inaccessible form labels also breach WCAG 2.2 SC 1.3.1 (Info and Relationships) and SC 4.1.2 (Name, Role, Value), excluding screen-reader users from your product.
Info because this is a UX polish concern, not a direct security vulnerability — authentication still functions, but duplicate submissions and silent failures degrade trust.
Disable the submit button and show a spinner or skeleton while the authentication request is pending, render server-returned error messages in an aria-live="polite" region next to the form, and bind every input to a visible <label htmlFor>. Wire this into your login component file such as src/app/(auth)/login/page.tsx or src/components/auth/LoginForm.tsx:
const [pending, setPending] = useState(false);
const [error, setError] = useState<string | null>(null);
async function onSubmit(data: FormData) {
setPending(true);
setError(null);
const res = await signIn(data);
setPending(false);
if (!res.ok) setError(res.message);
}
return (
<form onSubmit={handleSubmit(onSubmit)}>
<label htmlFor="email">Email</label>
<input id="email" {...register('email')} disabled={pending} />
{error && <p role="alert" aria-live="polite">{error}</p>}
<button type="submit" disabled={pending}>
{pending ? 'Signing in…' : 'Sign in'}
</button>
</form>
);
saas-authentication.session-management.login-ui-feedbackinfo"Login form at src/app/(auth)/login/page.tsx has no loading state — users can submit multiple times while the request is pending".src/app/login/page.tsx or src/components/auth/LoginForm.tsx.