When an application supports both email/password login and Google OAuth, it is tempting to send both paths through exactly the same post-authentication check.
For example: if the user has no email_verified_at, block access.
At first glance, that looks consistent. But different authentication methods may provide different guarantees about the email address.
The same destination does not mean the system received the same evidence before reaching it.
Password Login Often Needs a Separate Local Email Verification Step
During normal registration, a user can type an email address they do not control.
A password proves only that the person knows the secret for that account. It does not prove ownership of the mailbox.
That is why a local verification email has a separate purpose: the application verifies that the user can receive mail at the supplied address.
Google OAuth Can Provide an Already Verified Email Address
In a Google OAuth / OpenID Connect flow, the application receives identity information from an external provider.
If a properly validated provider token contains an email address and a verified-email signal, the system has different evidence than it does after a plain registration form.
In that case, repeating local verification of the same address may be redundant if that matches the product policy.
$providerEmailVerified = (bool) $oauthUser->emailVerified; if ($providerEmailVerified) { $user->email_verified_at ??= now();}OAuth Alone Does Not Automatically Prove the Email Address
An important detail: the fact that login happened through OAuth does not automatically mean every returned email should be treated as verified.
The application must rely on the contract of the specific provider and the validated claims it returns.
If the provider does not give a trustworthy verified-email signal, local verification may still be required.
If Local Email Verification Is Disabled, It Must Not Remain a Hidden Access Gate
A separate class of bugs appears when the product allows local email verification to be disabled while some code still checks email_verified_at.
The configuration says "verification is disabled," but real behavior continues to block users.
This is especially visible with OAuth: the user successfully completes external authentication and is then redirected to a local verification screen the product should not require at all.
Centralize the Email Verification Policy Instead of Scattering verified_at Checks
final class EmailVerificationPolicy{ public function isRequiredFor( User $user, LoginMethod $method, ): bool { if (! config('auth.email_verification_enabled')) { return false; } if ( $method === LoginMethod::GOOGLE && $user->email_verified_at !== null ) { return false; }The value of such a class is not its name but the fact that the decision becomes explicit.
All login methods ask one policy, while the policy can account for different guarantees and the global product setting.
This is safer than dozens of $user->email_verified_at === null checks scattered across middleware, controllers, callbacks, and post-login redirects.
A Decision Matrix Is Often Clearer Than One Universal if
Password registration- local verification ON- email not verified=> require verification Password login- local verification OFF=> do not block by email_verified_at Google OAuth- provider email verified- local verification ON=> local verification may be skipped Google OAuth- provider email not verified / unknownA Separate Problem Appears When OAuth Returns an Existing Account Email
If Google returns an email that already exists in the local database, do not automatically treat that as a simple login without an explicit account-linking rule.
The product should decide in advance whether an external identity may be linked to an existing user by email match alone or whether additional confirmation is required.
This is a separate security decision and should not be mixed with email verification itself.
A Verified Login Email Does Not Cover a Future Email Change
Even if an address was verified through Google during signup or login, that does not mean any future replacement address can be accepted without verification.
Email change has its own trust boundary, which I covered separately in the article about safely changing an email address by confirming the new address first.
Email Verification Should Not Quietly Become a General Authorization Policy
After successful login, the system already knows who the user is. The question "is this email verified?" may then be a separate prerequisite for certain features.
That is not the same thing as roles, permissions, or authorization for a specific business action.
I covered that distinction in more detail in the separate article about the difference between authentication and authorization.
The OAuth Callback Should Normalize Local State
When the external provider gives a sufficient guarantee about the email address, it is usually better to normalize that once into local state rather than repeatedly ask "did this user come through Google?"
For example, after a verified OAuth callback, the application can set email_verified_at. Later logic can then rely on a local verification fact rather than login history.
OAuth Login Must Not Accidentally Downgrade Existing Verified State
If a local user already has a verified email, a later OAuth login should not clear that state merely because a claim is missing or incomplete.
Where possible, local trust state should be monotonic: stronger evidence may increase trust, but weaker evidence should not downgrade it without an explicit reason.
What to Test
1. Password registration + verification ON: unverified user is blocked. 2. Password login + verification OFF: user is not blocked by email_verified_at. 3. Google OAuth + provider verified email: local verified state is created or preserved. 4. Google OAuth + provider email not verified: local verification is still required when enabled. 5. Google OAuth + verification OFF: no verification redirect is produced. 6. Existing verified user:One Check for Every Login Method Is Not Always the Right Abstraction
Password login, Google OAuth, and future providers may all lead into the same application, but they do not necessarily provide the same guarantees about an email address.
Instead of forcing one universal flow, model an explicit policy: is local verification enabled, is the address verified, where did that evidence come from, and is it sufficient for this scenario?
The right abstraction does not force every login method to behave identically. It makes every method explain clearly why the user is allowed to continue.
The same business goal of signing in does not mean every authentication method should follow identical technical steps.



