375 one time email verification#452
Conversation
There was a problem hiding this comment.
Pull request overview
Implements a one-time email verification flow for email/password users by requiring emailVerified for “signed in” status, sending verification “magic links”, and presenting a dedicated verification UI when a user is authenticated but unverified.
Changes:
- Added
SignInState.awaitingEmailVerificationand updated sign-in gating to requireemailVerified. - Implemented sending/handling of email sign-in links and
verifyAndChangeEmailaction codes inUserService, with pending link state stored in shared preferences. - Added a verification screen that lets users resend the link and edit/resend when they mistyped their email.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 10 comments.
| File | Description |
|---|---|
client/lib/features/user/data/services/user_service.dart |
Adds email-link verification helpers, URL handling for auth action codes, and changes “signed in” semantics to require verified email. |
client/lib/core/widgets/initial_loading_widget.dart |
Displays a new verification screen when the user is signed in but email-unverified; provides resend/edit UX. |
client/lib/core/data/services/shared_preferences_service.dart |
Persists pending verification email + timestamp to support email-link handling and expiry messaging. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| await sharedPreferencesService.clearPendingEmailVerification(); | ||
| await _firebaseAuth.signInWithEmailLink(email: email, emailLink: emailLink); |
| Future<void> sendMagicVerificationLink(String email) async { | ||
| _emailVerificationError = null; | ||
| await sharedPreferencesService.setPendingEmailVerification(email); | ||
| await _firebaseAuth.sendSignInLinkToEmail( | ||
| email: email, |
| String? get emailVerificationError => _emailVerificationError; | ||
|
|
||
| Future<void> sendMagicVerificationLink(String email) async { | ||
| _emailVerificationError = null; |
| } | ||
|
|
||
| Future<void> updateEmailAndResendVerification(String newEmail) async { | ||
| await _currentUser?.verifyBeforeUpdateEmail( |
| oobCode != null) { | ||
| _verifyAndChangeEmailHandled = true; | ||
| await _firebaseAuth.applyActionCode(oobCode); | ||
| // authStateChanges fires again with the updated verified user — return early here. |
| final svc = context.watch<UserService>(); | ||
| final email = svc.firebaseAuth.currentUser?.email ?? ''; | ||
| final linkError = svc.emailVerificationError; | ||
| return Scaffold( |
| Future<void> _resend() async { | ||
| final email = userService.firebaseAuth.currentUser?.email; | ||
| if (email == null) return; |
| if (!user.isAnonymous && !user.emailVerified) { | ||
| _signInState = SignInState.awaitingEmailVerification; | ||
| } else { | ||
| _signInState = SignInState.signedIn; | ||
| } |
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
…karenunify/kh into 375-one-time-email-verification
|
@katherineqian if you wouldn't mind deploying this branch to the staging environment so I can test the verification email from Firebase Auth is actually being sent and works (rather than the mocked link generated in the local auth emulator), that would be much appreciated! I believe this is the only change that's needed in Firebase Console/Auth of the project for the email verification to work:
|
|
Hi @karenunify, thank you for leading this work! Here is the preview deployment I generated: https://gen-hls-bkc-7627--email-verification-4-74t50cj1.web.app/ I also enabled passwordless sign-in as shown below. |
|
@katherineqian I'm working on fixing this PR! I think I have too much built in to work with the local auth emulator, rather than allowing a the firebase authentication to work its own magic. I'll let you know when it's ready to be redeployed to staging, and in the meantime feel free to deploy any other branch that might need testing. Thank you!! |
|
@katherineqian when you have a chance, could you redeploy this branch to staging? I've hopefully simplified the flow a bit. |
|
Hi @karenunify, here is the new preview link! Will also send on Slack :) https://gen-hls-bkc-7627--email-verification-new-umc5m3nu.web.app |
|
@katherineqian or @mikewillems, whenever you have a spare moment, could one of you deploy the latest updates to this branch to staging, and update the whitelisted domains to match in firebase? Thank you!!! |
|
@katherineqian whenever you have a moment, could you deploy the latest updates to this branch to staging, and update the whitelisted domains to match in firebase? Thank you!!! |
| ), | ||
| ), | ||
| SizedBox(height: 9), | ||
| if (_formError.isNotEmpty) AccountErrorMessage(errorCode: _formError), |
There was a problem hiding this comment.
Hi @karenunify! @mwmarino pointed me to an issue in your changes that I investigated on his behalf. It looks like AccountErrorMessage is being shown twice when there is a _formError. It's should show only above the form. Thanks!
There was a problem hiding this comment.
@johnnycrich eeek! My apologies! Will get this cleaned up asap!
|
@katherineqian I think this is finally ready for review. A couple things to note:
|
|
Great, thank you @karenunify for all your hard work and revisions on this! I will take a look. Updated preview link here for anyone else testing: https://gen-hls-bkc-7627--email-verification-0611-69kazsg5.web.app/ |

What is in this PR?
One time email verification on sign-up/login if not already verified using Firebase Auth.
Changes in the codebase
When a user creates a new account or is logging back in, once their email is submitted, a query is made to Firebase Auth to see if that user's email has been verified. When creating the account, they see a page prompting them to check their email and verify their account with a link that is valid for 30 minutes and should not be able to get past that page until their email is verified. Same when logging back in with an existing account that has not had the email verified.
Changes outside the codebase
The app domain needs to be whitelisted in Firebase Auth, and Firebase Auth email verification template/action settings need to be modified:
Testing this PR
Create a new account:
Log in with an existing account where the user has not verified their email:
PR Checklist
AI tools used (if applicable):
Claude Code extension in VS code for best practices and debugging