Skip to content

375 one time email verification#452

Open
karenunify wants to merge 22 commits into
berkmancenter:stagingfrom
karenunify:375-one-time-email-verification
Open

375 one time email verification#452
karenunify wants to merge 22 commits into
berkmancenter:stagingfrom
karenunify:375-one-time-email-verification

Conversation

@karenunify

@karenunify karenunify commented May 22, 2026

Copy link
Copy Markdown
Collaborator

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:

  • In the Firebase console, go to Security > Authentication.
  • In the Sign-in method tab, enable the Email/Password sign-in method. Note that email/password sign-in must be enabled to use email link sign-in.
  • In the same section, enable the Email link (passwordless sign-in) sign-in provider.
  • Click Save.

Testing this PR

Create a new account:

  • after signing up, a user should be redirected to a page prompting them to verify their email
  • they should not be able to get past this page until email has been verified, either by refreshing the page, or signing in from another tab

Log in with an existing account where the user has not verified their email:

  • once submitting their email/password, an existing user should be redirected to a page prompting them to verify their email
  • they should not be able to get past this page until email has been verified, either by refreshing the page, or signing in from another tab

PR Checklist

  • [ x] Where applicable, I have added localization (l10n) entries to my feature for user-facing text.

AI tools used (if applicable):
Claude Code extension in VS code for best practices and debugging

Copilot AI review requested due to automatic review settings May 22, 2026 18:05
@karenunify karenunify marked this pull request as draft May 22, 2026 18:06

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.awaitingEmailVerification and updated sign-in gating to require emailVerified.
  • Implemented sending/handling of email sign-in links and verifyAndChangeEmail action codes in UserService, 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.

Comment thread client/lib/features/user/data/services/user_service.dart Outdated
Comment on lines +91 to +92
await sharedPreferencesService.clearPendingEmailVerification();
await _firebaseAuth.signInWithEmailLink(email: email, emailLink: emailLink);
Comment thread client/lib/features/user/data/services/user_service.dart Outdated
Comment on lines +55 to +59
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.
Comment on lines +209 to +212
final svc = context.watch<UserService>();
final email = svc.firebaseAuth.currentUser?.email ?? '';
final linkError = svc.emailVerificationError;
return Scaffold(
Comment on lines +186 to +188
Future<void> _resend() async {
final email = userService.firebaseAuth.currentUser?.email;
if (email == null) return;
Comment on lines +226 to +230
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 karenunify marked this pull request as ready for review May 26, 2026 18:11
@karenunify

Copy link
Copy Markdown
Collaborator Author

@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:

  • Enable the "Email link (passwordless sign-in)" method under Authentication → Sign-in methods in the Firebase console

@katherineqian

katherineqian commented May 27, 2026

Copy link
Copy Markdown
Collaborator

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.
Screenshot 2026-05-27 at 10 26 26

@karenunify

Copy link
Copy Markdown
Collaborator Author

@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!!

@karenunify

Copy link
Copy Markdown
Collaborator Author

@katherineqian when you have a chance, could you redeploy this branch to staging? I've hopefully simplified the flow a bit.

@katherineqian

Copy link
Copy Markdown
Collaborator

Hi @karenunify, here is the new preview link! Will also send on Slack :) https://gen-hls-bkc-7627--email-verification-new-umc5m3nu.web.app

@karenunify

Copy link
Copy Markdown
Collaborator Author

@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 katherineqian self-requested a review June 8, 2026 21:34
@karenunify

Copy link
Copy Markdown
Collaborator Author

@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),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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!

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@johnnycrich eeek! My apologies! Will get this cleaned up asap!

@karenunify

karenunify commented Jun 12, 2026

Copy link
Copy Markdown
Collaborator Author

@katherineqian I think this is finally ready for review. A couple things to note:

  • In the verify_email_page.dart there are 2 blocks of commented out code which is terrible, I know. The reason for this is the requirements in the ticket specify allowing users to modify their email address right after account creation in the case of a type, however during Matt's design review it was determined confusing/unnecessary at that point. I was going to bring it up at the next sync
  • Users are still being shown the Firebase auth confirmation page, rather than being redirected to the app, despite following Firebase's documentation to avoid this. While this isn't ideal, it is not a show stopper while I continue to look into it.

@katherineqian

Copy link
Copy Markdown
Collaborator

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/

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants