firebase-functions icon indicating copy to clipboard operation
firebase-functions copied to clipboard

Incorrect emailVerified Status Returned as false for Microsoft Provider in functions.auth.user().onCreate()

Open AmilKey opened this issue 1 year ago • 5 comments

Related issues

I did not find any related issues that address this specific problem.

[REQUIRED] Version info

node: v18.20.3

firebase-functions: 5.0.1

firebase-tools: 13.11.2

firebase-admin: 12.2.0

[REQUIRED] Test case

I have a Firebase Cloud Function that triggers on user creation (functions.auth.user().onCreate()). When a user registers using the Microsoft authentication provider, the emailVerified field is returned as false in the user object, even though the Microsoft account has a verified email.

[REQUIRED] Steps to reproduce

  1. Set up Firebase Authentication with Microsoft as a provider.
  2. Create a Cloud Function that triggers on user creation (functions.auth.user().onCreate()).
  3. Register a new user using the Microsoft provider.
  4. Inspect the emailVerified field in the user object within the triggered Cloud Function.

[REQUIRED] Expected behavior

The emailVerified field should be true when the user registers using the Microsoft provider, as the email is verified by Microsoft during their authentication process.

[REQUIRED] Actual behavior

The emailVerified field is returned as false for users registering with the Microsoft provider, even though the email should be considered verified by Microsoft.

result User into hook

{
  "uid": "BLTZuXMlmxSotyULCIifeenCxE82",
  "email": "[email protected]",
  "emailVerified": false,
  "displayName": "My Name",
  "photoURL": null,
  "phoneNumber": null,
  "disabled": false,
  "passwordHash": null,
  "passwordSalt": null,
  "tokensValidAfterTime": null,
  "metadata": {
    "creationTime": "2024-08-14T05:55:07Z",
    "lastSignInTime": "2024-08-14T05:55:07Z"
  },
  "customClaims": {},
  "providerData": [
    {
      "displayName": "My Name",
      "email": "[email protected]",
      "providerId": "microsoft.com",
      "uid": "c0698c11-44b8-41ed-9f2c-8f431484a35e",
      "toJSON": "[Function (anonymous)]"
    }
  ]
}

Note: Locally in the emulator, this works as expected, and the emailVerified field is set to true.

Were you able to successfully deploy your functions?

Yes, the functions deploy successfully without any errors.

AmilKey avatar Aug 14 '24 06:08 AmilKey

Hey @AmilKey. Does this happen with Microsoft provider only, or any others?

exaby73 avatar Aug 15 '24 14:08 exaby73

Hey @AmilKey. Does this happen with Microsoft provider only, or any others?

with Microsoft provider only

AmilKey avatar Aug 15 '24 15:08 AmilKey

I'm noticing this same behavior when using the Firebase Authentication JS SDK.

The reason it is an issue in our case is because the automatic account linking of multiple providers does not work for Microsoft. In the Firebase console for our project under the Authentication > Settings > User account linking section we have the "Link accounts that use the same email" setting enabled. This works properly for the Google and Email Link sign-in methods but not for Microsoft which returns the error auth/account-exists-with-different-credential on sign in. My assumption is that it's related to the fact that the Microsoft provider info returns with emailVerified as false.

agramian avatar Jan 25 '25 04:01 agramian

Reproduced this issue. With Google authentication, emailVerified returns true, but this is not the case with Microsoft authentication.

CorieW avatar Apr 16 '25 13:04 CorieW

For now, you could use and deploy something like the following function:

import {
  beforeUserSignedIn,
} from "firebase-functions/v2/identity";

export const beforeSignIn2 = beforeUserSignedIn((event) => {
  if (!event.data?.providerData) return;

  for (const provider of event.data?.providerData) {
    if (provider?.providerId === "microsoft.com") {
      return {
        emailVerified: true
      };
    }
  }
});

CorieW avatar Apr 16 '25 14:04 CorieW

Is this truly an error/bug, or can we not trust that Microsoft SSO logins are from "real" emails?

trullock avatar Jan 06 '26 20:01 trullock

From various sources:

When implementing Microsoft Single Sign-On (SSO) in an application, you cannot automatically trust the email address provided in the identity token as having been verified by Microsoft, and it should not be used as a unique, primary identifier for a user across different services. Why the Email Claim is Not Implicitly Verified Mutable and Unverified: The email claim (attribute) in the token is considered both mutable (changeable) and unverified by default in many scenarios. Microsoft's documentation advises developers not to rely on this claim alone to uniquely identify a user. Account Merging Risks: If your application automatically merges accounts from different identity providers (IdPs) based solely on an email address claim, you create a potential security vulnerability (account takeover risk), as an attacker might be able to use an unverified email to access an existing account. Protocol Specification: The OpenID Connect (OIDC) protocol, which is used for modern Microsoft Entra ID (formerly Azure AD) authentication, states that it is generally unsafe to rely on the Identity Provider to verify the email claim with a high level of assurance.

https://www.threatdown.com/blog/microsoft-azure-ad-flaw-can-lead-to-account-takeover/#:~:text=There%20is%20one%20caveat%20for,or%20used%20as%20an%20identifier.

There is one caveat for the attacker though. Not all sites and services use the email address as a unique identifier.

The researchers have informed Microsoft and other stakeholders of the issue and steps are being taken to thwart this type of account takeover.

Microsoft already had existing documentation informing developers not to use the “email” claim as a unique identifier in the access token, and after the disclosure it published a dedicated page on Claims Validation with all the information a developer needs to consider when implementing authentication.

The researchers say they tested their proof-of-concept on hundreds of websites and applications and found many of them vulnerable. They shared the PoC with each affected organization and informed them of the vulnerability. While most of the affected apps were quick to respond and fix the issue, the number of tested apps was just a drop in the ocean of the Internet.

So, if you are running a site or service that uses Azure AD as an IdP, please check that you do not accept the Email attribute, because the email claim is both mutable and unverified so it should never be trusted or used as an identifier.

https://learn.microsoft.com/en-us/answers/questions/812672/microsoft-openid-connect-getting-verified-email

I'm the lead Product Manager for our authentication libraries at Microsoft. Please never use email or perferred_email for authorization decisions. Emails are unverified in enterprise systems like Azure AD and can be set programmatically to any value by the tenant administrator. If you are looking for a claim that uniquely identifies a user, please use the user's object id (oid). It guaranteed to be unique and persistent.

We have detailed guidance on how to validate claims in the token here:

https://learn.microsoft.com/en-us/azure/active-directory/develop/claims-validation

trullock avatar Jan 06 '26 20:01 trullock

So this looks to be correct, you shouldn't trust email addresses from MS logins

trullock avatar Jan 06 '26 20:01 trullock