feat(auth): add configurable email verification enforcement
Auth:RequireEmailVerification (default off) gates whether local register requires confirming email before login. OAuth new-user paths are untouched -- Google/Microsoft already assert a verified email. Adds verify-email and resend-verification-email endpoints, mirroring the existing reset-password enumeration-avoidance and rate-limiting patterns, plus a login-embedded resend affordance and a verify-email landing page on the frontend. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -137,4 +137,33 @@ describe('LoginPage', () => {
|
||||
|
||||
expect(await screen.findByRole('alert')).toHaveTextContent('Too many attempts. Please wait a few minutes and try again.');
|
||||
});
|
||||
|
||||
it('offers a resend-verification action when login reports the account is not verified', async () => {
|
||||
mockedApi.get.mockResolvedValueOnce({
|
||||
data: { requireAuth: false, googleEnabled: false, microsoftEnabled: false, localEnabled: true, allowRegistration: false, requireEmailVerification: true },
|
||||
} as any);
|
||||
mockedApi.post.mockImplementation((url: string) => {
|
||||
if (url === '/auth/login') {
|
||||
return Promise.reject({ response: { status: 403, data: { error: 'email_not_verified' } } });
|
||||
}
|
||||
if (url === '/auth/resend-verification-email') {
|
||||
return Promise.resolve({ data: {} } as any);
|
||||
}
|
||||
return Promise.resolve({ data: {} } as any);
|
||||
});
|
||||
|
||||
renderLoginPage();
|
||||
await screen.findByLabelText('Email');
|
||||
|
||||
await userEvent.type(screen.getByLabelText('Email'), 'unverified@example.com');
|
||||
await userEvent.type(screen.getByLabelText('Current password'), 'hunter2');
|
||||
await userEvent.click(screen.getByRole('button', { name: 'Sign in' }));
|
||||
|
||||
expect(await screen.findByText('Please verify your email address before signing in.')).toBeInTheDocument();
|
||||
|
||||
await userEvent.click(screen.getByRole('button', { name: 'Resend verification email' }));
|
||||
|
||||
await waitFor(() => expect(mockedApi.post).toHaveBeenCalledWith('/auth/resend-verification-email', { email: 'unverified@example.com' }));
|
||||
await screen.findByText('Verification email sent. Check your inbox.');
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user