Skip to content

add 'VERIFY_AND_CHANGE_EMAIL' linkType for generateEmailActionLink#705

Merged
macastelaz merged 34 commits into
firebase:devfrom
utamori:dev
Jun 5, 2026
Merged

add 'VERIFY_AND_CHANGE_EMAIL' linkType for generateEmailActionLink#705
macastelaz merged 34 commits into
firebase:devfrom
utamori:dev

Conversation

@utamori
Copy link
Copy Markdown

@utamori utamori commented Jul 10, 2025

Summary

  • Add support for VERIFY_AND_CHANGE_EMAIL linkType in Firebase Auth email action links
  • Implement VerifyAndChangeEmailLink and VerifyAndChangeEmailLinkWithSettings methods
  • Add comprehensive tests for the new functionality including tenant integration tests

Changes

  • Added verifyAndChangeEmail linkType constant
  • Updated generateEmailActionLink to accept optional newEmail parameter
  • Added new public methods for verify and change email functionality
  • Updated existing methods to use the new signature
  • Added unit tests and integration tests

Test plan

  • Unit tests for new functionality
  • Integration tests for tenant-aware scenarios
  • Existing tests continue to pass

This addresses the feature request in #470 by providing the ability to generate email action links for email verification and change flows.

@utamori utamori marked this pull request as draft July 10, 2025 12:47
@utamori utamori marked this pull request as ready for review June 4, 2026 05:21
Comment thread auth/email_action_links.go Outdated
}

if linkType == verifyAndChangeEmail {
if newEmail == nil {
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Do we also need to check for || *newEmail == "" in case an empty string is passed in here?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Thanks. I'll fix it now.

Comment thread auth/email_action_links.go Outdated

if linkType == verifyAndChangeEmail {
if newEmail == nil {
return "", errors.New("newEmail must not be nil when linkType is verifyAndChangeEmail")
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

nit: "newEmail must be not be empty when linkType is verifyAndChangeEmail"

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Thanks. I'll fix it now.


if _, err := client.EmailSignInLink(context.Background(), "", testActionCodeSettings); err == nil {
t.Errorf("EmailSignInLink('') = nil; want error")
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Should we add a test case for client.VerifyAndChangeEmailLink being called without an email for the sake of consistency?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Thanks. I'll fix it now.

}
}

func TestEmailActionLinkNoEmail(t *testing.T) {
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Should we have a test for when VerifyAndChangeEmailLink is called with empty/nil newEmail?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Thanks. I'll fix it now.

Comment thread auth/email_action_links.go Outdated
}

// VerifyAndChangeEmailLink generates the out-of-band email action link for email verification and change flows for the
// specified email address.
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

nit: "// specified current email address and new email address" to clarify there are two email addresses needed for this function.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Thanks. I'll fix it now.

Comment thread auth/email_action_links.go Outdated

func (c *baseClient) generateEmailActionLink(
ctx context.Context, linkType linkType, email string, settings *ActionCodeSettings) (string, error) {
ctx context.Context, linkType linkType, email string, settings *ActionCodeSettings, newEmail *string) (string, error) {
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

I wonder if it may make sense to make this a variadic function now, making the last argument something like: "opts ...emailActionLinkOption,"

emailActionLinkOption would be something like "type emailActionLinkOption func(map[string]interface{})"

and then we'd define:

"
func withNewEmail(newEmail string) emailActionLinkOption {
return func(payload map[string]interface{}) {
payload["newEmail"] = newEmail
}
}
"

With this in place, existing call sites of generateEmailActionLink can remain unchanged (no need to pass a trailing nil) .

The new call site (VerifyAndChangeEmailLinkWithSettings) can look like this:

"
func (c *baseClient) VerifyAndChangeEmailLinkWithSettings(
ctx context.Context, email string, newEmail string, settings
*ActionCodeSettings) (string, error) {
if newEmail == "" {
return "", errors.New("newEmail must not be empty")
}
return c.generateEmailActionLink(ctx, verifyAndChangeEmail, email,
settings, withNewEmail(newEmail))
}
"

From my vantage point, the main advantage here is scalability. The tradeoff is the code becomes a bit more verbose and I don't know of any current needs to support additional similar options any time soon, so this may fall into the YAGNI. I'd be curious to hear your thoughts on this!

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Thanks! I tried it out and it worked perfectly, so I'll go with your suggestion.

@macastelaz macastelaz self-assigned this Jun 4, 2026
@utamori utamori requested a review from macastelaz June 4, 2026 23:40
Copy link
Copy Markdown

@macastelaz macastelaz left a comment

Choose a reason for hiding this comment

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

Thanks for the contribution and making the suggested changes!

@macastelaz
Copy link
Copy Markdown

Sorry I didn't catch this earlier - per the contribution guidelines, can you instead merge into the dev branch instead of master (see: https://github.com/firebase/firebase-admin-go?tab=contributing-ov-file)

Thanks!

@macastelaz macastelaz changed the base branch from master to dev June 5, 2026 14:49
@macastelaz
Copy link
Copy Markdown

Sorry I didn't catch this earlier - per the contribution guidelines, can you instead merge into the dev branch instead of master (see: https://github.com/firebase/firebase-admin-go?tab=contributing-ov-file)

Thanks!

Ooops - I forgot I could change this myself. None-the-less, if you have future contributions to make, feel free to target the dev branch directly.

Thanks again for the contribution here!

@macastelaz macastelaz merged commit 07b1814 into firebase:dev Jun 5, 2026
10 checks passed
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