Коли застосунок підтримує і звичайний вхід за email та паролем, і Google OAuth, дуже спокусливо провести обидва сценарії через одну й ту саму перевірку після автентифікації.
Наприклад: якщо в користувача немає email_verified_at, не пускати його далі.
На перший погляд це виглядає послідовно. Але різні способи входу можуть давати різні гарантії щодо адреси email.
Однакова точка входу не означає однаковий набір доказів, які система отримала до цієї точки.
Для парольного входу локальне підтвердження email часто є окремим кроком
Під час звичайної реєстрації користувач може ввести будь-яку адресу, до якої він не має доступу.
Пароль доводить лише те, що людина знає секрет для цього облікового запису. Він сам по собі не доводить володіння поштовою скринькою.
Саме тому локальний лист із посиланням підтвердження має окремий сенс: застосунок сам перевіряє, що користувач може отримати повідомлення на вказану адресу.
Google OAuth може приходити з уже підтвердженою адресою
У Google OAuth / OpenID Connect сценарії застосунок отримує ідентичність від зовнішнього провайдера.
Якщо валідований токен провайдера містить email і ознаку, що ця адреса підтверджена, система вже має інший набір доказів, ніж після простої форми реєстрації.
У такому випадку повторна локальна перевірка тієї самої адреси може бути зайвою, якщо це відповідає політиці продукту.
$providerEmailVerified = (bool) $oauthUser->emailVerified; if ($providerEmailVerified) { $user->email_verified_at ??= now();}Не можна пропускати підтвердження email лише тому, що це OAuth
Важлива деталь: сам факт OAuth-входу ще не означає, що будь-який email треба автоматично вважати підтвердженим.
Потрібно дивитися на контракт конкретного провайдера і на перевірені claims, які він повертає.
Якщо провайдер не дає надійної ознаки підтвердження адреси, локальне підтвердження email усе ще може бути потрібним.
Якщо локальне підтвердження email вимкнене, воно не повинно лишатися прихованою умовою доступу
Окремий клас помилок виникає, коли продукт дозволяє вимкнути локальне підтвердження email, але частина коду все одно продовжує перевіряти email_verified_at.
Тоді налаштування формально говорить "підтвердження email вимкнене", а реальна поведінка все ще блокує користувачів.
Для OAuth це особливо помітно: користувач успішно проходить зовнішню автентифікацію, але потім потрапляє на локальну сторінку підтвердження email, який продукт узагалі не повинен вимагати.
Краще мати одну явну політику, а не розкидані перевірки verified_at
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; }Сенс такого класу не в самій назві, а в тому, що рішення стає явним.
Усі сценарії входу питають одну політику, але політика може врахувати різні гарантії та глобальне налаштування продукту.
Це краще, ніж десятки перевірок $user->email_verified_at === null у middleware, controller, callback і після перенаправлення після входу.
Одна матриця рішень часто зрозуміліша за один універсальний 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 / unknownОкрема проблема - коли OAuth повертає email уже існуючого облікового запису
Якщо Google повернув email, який уже є в локальній базі, не варто автоматично вважати це простим входом без окремого правила зв’язування облікових записів.
Потрібно заздалегідь визначити, чи можна прив’язувати зовнішню ідентичність до існуючого користувача лише за збігом email, чи потрібне додаткове підтвердження.
Це вже окреме рішення безпеки, і його краще не змішувати з питанням email verification.
Підтверджений email під час входу не скасовує перевірку майбутньої зміни email
Навіть якщо адреса була підтверджена через Google під час створення або входу, це не означає, що будь-яку нову адресу користувача теж можна прийняти без перевірки.
Зміна email має власну межу довіри. Я окремо розбирала її в матеріалі про безпечну зміну email із підтвердженням нової адреси.
Підтвердження email не повинно непомітно перетворюватися на загальне правило авторизації
Після успішного входу система вже знає, хто користувач. Далі питання "чи підтверджений email?" може бути окремою умовою доступу до певних можливостей.
Але це не те саме, що ролі, дозволи або право виконати конкретну бізнес-операцію.
Цю різницю я детальніше описувала в окремій статті про різницю між автентифікацією та авторизацією.
OAuth callback краще завершувати нормалізацією локального стану
Коли зовнішній провайдер дав достатню гарантію щодо email, це краще один раз відобразити в локальній моделі, а не щоразу питати "цей користувач прийшов через Google чи ні?".
Наприклад, після перевіреного OAuth callback можна встановити email_verified_at. Тоді подальша логіка працює з локальним фактом підтвердження, а не з історією способу входу.
Вхід через OAuth не повинен випадково погіршувати вже підтверджений локальний стан
Якщо локальний користувач уже має підтверджений email, повторний вхід через OAuth не повинен скидати цей стан лише через відсутній або неповний claim.
Оновлення локального стану має бути монотонним там, де це можливо: новий доказ може підвищити рівень довіри, але слабший сигнал не повинен без причини його знижувати.
Що варто перевірити тестами
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:Одна перевірка для всіх способів входу не завжди є правильною абстракцією
Парольний вхід, Google OAuth і майбутні провайдери можуть приводити користувача до одного застосунку, але вони не обов’язково дають однакові гарантії щодо email.
Тому краще моделювати не "один універсальний сценарій", а явну політику: чи ввімкнене локальне підтвердження email, чи підтверджена адреса, звідки взявся цей доказ і чи достатній він для конкретного сценарію.
Правильна абстракція не змушує всі способи входу поводитися однаково. Вона змушує їх однаково явно пояснювати, чому користувач уже може пройти далі.
Однакова бізнес-мета входу не означає, що всі способи автентифікації повинні проходити однакові технічні кроки.



