[GH-ISSUE #7787] [generic-oauth] Microsoft entra id plugin not handling personal microsoft account name #10904

Open
opened 2026-04-13 07:17:37 -05:00 by GiteaMirror · 3 comments
Owner

Originally created by @EjsenKirie on GitHub (Feb 4, 2026).
Original GitHub issue: https://github.com/better-auth/better-auth/issues/7787

Is this suited for github?

  • Yes, this is suited for github

To Reproduce

Create a multi-tenant app registration with audience set to Accounts in any Microsoft Entra directory and personal Microsoft accounts enabled. Add the app registration to better-auth as a provider utilizing the microsoftEntraId provider helper. Proceed to login with a personal microsoft account.

Current vs. Expected behavior

Currently, the getUserInfo helper for entra id are unable to map the user name, resulting in a name_is_missing error.

What version of Better Auth are you using?

1.4.18

System info

{
  "system": {
    "platform": "linux",
    "arch": "x64",
    "version": "#1 SMP PREEMPT_DYNAMIC Thu Jun  5 18:30:46 UTC 2025",
    "release": "6.6.87.2-microsoft-standard-WSL2",
    "cpuCount": 8,
    "cpuModel": "Intel(R) Core(TM) Ultra 7 268V",
    "totalMemory": "15.40 GB",
    "freeMemory": "5.18 GB"
  },
  "node": {
    "version": "v20.20.0",
    "env": "development"
  },
  "packageManager": {
    "name": "npm",
    "version": "10.8.2"
  },
  "frameworks": [
    {
      "name": "svelte",
      "version": "^5.45.2"
    },
    {
      "name": "@sveltejs/kit",
      "version": "^2.49.5"
    }
  ],
  "databases": [
    {
      "name": "@prisma/client",
      "version": "^7.3.0"
    }
  ],
  "betterAuth": {
    "version": "^1.4.18",
    "config": null
  }
}

Which area(s) are affected? (Select all that apply)

Package

Auth config (if applicable)


Additional context

The issue seems to be that the betterFetch<MicrosoftEntraIdProfile> response differs between personal and work accounts:

https://github.com/better-auth/better-auth/blob/9f40c35ee428b0313c90089d857b219b911a51ca/packages/better-auth/src/plugins/generic-oauth/providers/microsoft-entra-id.ts#L59-L66

Personal accounts are returning profile.givenname and profile.familyname while work accounts returns profile.given_name and profile.family_name, causing the mapping to fail for personal accounts:
https://github.com/better-auth/better-auth/blob/9f40c35ee428b0313c90089d857b219b911a51ca/packages/better-auth/src/plugins/generic-oauth/providers/microsoft-entra-id.ts#L74-L77

As a side note I noticed that the social provider for entra id is utilizing the id token by default:
https://github.com/better-auth/better-auth/blob/9f40c35ee428b0313c90089d857b219b911a51ca/packages/core/src/social-providers/microsoft-entra-id.ts#L184

Any reason the generic oauth helper cant do this as well?

Originally created by @EjsenKirie on GitHub (Feb 4, 2026). Original GitHub issue: https://github.com/better-auth/better-auth/issues/7787 ### Is this suited for github? - [x] Yes, this is suited for github ### To Reproduce Create a multi-tenant app registration with audience set to `Accounts in any Microsoft Entra directory and personal Microsoft accounts` enabled. Add the app registration to better-auth as a provider utilizing the `microsoftEntraId` provider helper. Proceed to login with a personal microsoft account. ### Current vs. Expected behavior Currently, the `getUserInfo` helper for entra id are unable to map the user `name`, resulting in a `name_is_missing` error. ### What version of Better Auth are you using? 1.4.18 ### System info ```bash { "system": { "platform": "linux", "arch": "x64", "version": "#1 SMP PREEMPT_DYNAMIC Thu Jun 5 18:30:46 UTC 2025", "release": "6.6.87.2-microsoft-standard-WSL2", "cpuCount": 8, "cpuModel": "Intel(R) Core(TM) Ultra 7 268V", "totalMemory": "15.40 GB", "freeMemory": "5.18 GB" }, "node": { "version": "v20.20.0", "env": "development" }, "packageManager": { "name": "npm", "version": "10.8.2" }, "frameworks": [ { "name": "svelte", "version": "^5.45.2" }, { "name": "@sveltejs/kit", "version": "^2.49.5" } ], "databases": [ { "name": "@prisma/client", "version": "^7.3.0" } ], "betterAuth": { "version": "^1.4.18", "config": null } } ``` ### Which area(s) are affected? (Select all that apply) Package ### Auth config (if applicable) ```typescript ``` ### Additional context The issue seems to be that the `betterFetch<MicrosoftEntraIdProfile>` response differs between personal and work accounts: https://github.com/better-auth/better-auth/blob/9f40c35ee428b0313c90089d857b219b911a51ca/packages/better-auth/src/plugins/generic-oauth/providers/microsoft-entra-id.ts#L59-L66 Personal accounts are returning `profile.givenname` and `profile.familyname` while work accounts returns `profile.given_name` and `profile.family_name`, causing the mapping to fail for personal accounts: https://github.com/better-auth/better-auth/blob/9f40c35ee428b0313c90089d857b219b911a51ca/packages/better-auth/src/plugins/generic-oauth/providers/microsoft-entra-id.ts#L74-L77 As a side note I noticed that the social provider for entra id is utilizing the id token by default: https://github.com/better-auth/better-auth/blob/9f40c35ee428b0313c90089d857b219b911a51ca/packages/core/src/social-providers/microsoft-entra-id.ts#L184 Any reason the generic oauth helper cant do this as well?
GiteaMirror added the oauthbug labels 2026-04-13 07:17:37 -05:00
Author
Owner

@dosubot[bot] commented on GitHub (Feb 4, 2026):

Hi @EjsenKirie! I'm Dosu and I’m helping the better-auth team.

The generic OAuth provider for Microsoft Entra ID in Better Auth fetches user info from the Microsoft Graph userinfo endpoint using the access token, which only maps fields like name, given_name, and family_name. This causes issues for personal Microsoft accounts, which return givenname and familyname instead, resulting in missing names and errors. There’s no documented reason in the code for why the generic provider doesn’t use the ID token like the social provider does, but this is the root cause of the inconsistency you’re seeing citation.

A practical workaround is to override the getUserInfo method in your provider config to decode the ID token and normalize the fields yourself, similar to how the social provider works citation. Here’s a sample approach:

import { decodeJwt } from "jose";

getUserInfo: async (token) => {
  if (!token.idToken) return null;
  const profile = decodeJwt(token.idToken);
  return {
    user: {
      id: profile.sub,
      name:
        profile.name ||
        [profile.given_name || profile.givenname, profile.family_name || profile.familyname]
          .filter(Boolean)
          .join(" ") ||
        undefined,
      email: profile.email || profile.preferred_username,
      image: profile.picture,
      emailVerified: profile.email_verified ?? false,
    },
    data: profile,
  };
}

This will ensure both personal and work accounts are handled consistently. If you need ID token verification (not just decoding), you’ll need to implement that manually, as it’s not currently supported for Microsoft providers in Better Auth citation.

Recent updates have improved type definitions for the social provider, but the generic OAuth provider hasn’t been updated to address this mapping issue yet citation. There’s ongoing discussion about improving normalization and documentation, but for now, overriding getUserInfo is the recommended solution.

To reply, just mention @dosu.


How did I do? Good | Irrelevant | Incorrect | Verbose | Hallucination | Report 🐛 | Other

Chat with Dosu Open in Cursor Join Discord Share on X

<!-- gh-comment-id:3846681399 --> @dosubot[bot] commented on GitHub (Feb 4, 2026): <!-- Greeting --> Hi @EjsenKirie! I'm [Dosu](https://go.dosu.dev/dosubot) and I’m helping the better-auth team. <!-- Answer --> The generic OAuth provider for Microsoft Entra ID in Better Auth fetches user info from the Microsoft Graph userinfo endpoint using the access token, which only maps fields like `name`, `given_name`, and `family_name`. This causes issues for personal Microsoft accounts, which return `givenname` and `familyname` instead, resulting in missing names and errors. There’s no documented reason in the code for why the generic provider doesn’t use the ID token like the social provider does, but this is the root cause of the inconsistency you’re seeing [citation](https://github.com/better-auth/better-auth/blob/583f12fb7db38681ee882d219ce3895faa4a6976/packages/better-auth/src/plugins/generic-oauth/providers/microsoft-entra-id.ts#L54-L86). A practical workaround is to override the `getUserInfo` method in your provider config to decode the ID token and normalize the fields yourself, similar to how the social provider works [citation](https://github.com/better-auth/better-auth/blob/583f12fb7db38681ee882d219ce3895faa4a6976/packages/core/src/social-providers/microsoft-entra-id.ts#L116-L236). Here’s a sample approach: ```typescript import { decodeJwt } from "jose"; getUserInfo: async (token) => { if (!token.idToken) return null; const profile = decodeJwt(token.idToken); return { user: { id: profile.sub, name: profile.name || [profile.given_name || profile.givenname, profile.family_name || profile.familyname] .filter(Boolean) .join(" ") || undefined, email: profile.email || profile.preferred_username, image: profile.picture, emailVerified: profile.email_verified ?? false, }, data: profile, }; } ``` This will ensure both personal and work accounts are handled consistently. If you need ID token verification (not just decoding), you’ll need to implement that manually, as it’s not currently supported for Microsoft providers in Better Auth [citation](https://github.com/better-auth/better-auth/issues/7776). Recent updates have improved type definitions for the social provider, but the generic OAuth provider hasn’t been updated to address this mapping issue yet [citation](https://github.com/better-auth/better-auth/pull/3806). There’s ongoing discussion about improving normalization and documentation, but for now, overriding `getUserInfo` is the recommended solution. <!-- Dosu Comment Footer --> *To reply, just mention [@dosu](https://go.dosu.dev/dosubot).* --- <sup>How did I do? [Good](https://app.dosu.dev/response-feedback/f09f41fd-7974-4919-b0d0-0bab4310621a?feedback_type=great_response) | [Irrelevant](https://app.dosu.dev/response-feedback/f09f41fd-7974-4919-b0d0-0bab4310621a?feedback_type=irrelevant_answer) | [Incorrect](https://app.dosu.dev/response-feedback/f09f41fd-7974-4919-b0d0-0bab4310621a?feedback_type=incorrect_sources) | [Verbose](https://app.dosu.dev/response-feedback/f09f41fd-7974-4919-b0d0-0bab4310621a?feedback_type=too_verbose) | [Hallucination](https://app.dosu.dev/response-feedback/f09f41fd-7974-4919-b0d0-0bab4310621a?feedback_type=hallucination) | [Report 🐛](https://app.dosu.dev/response-feedback/f09f41fd-7974-4919-b0d0-0bab4310621a?feedback_type=bug_report) | [Other](https://app.dosu.dev/response-feedback/f09f41fd-7974-4919-b0d0-0bab4310621a?feedback_type=other)</sup> [![Chat with Dosu](https://dosu.dev/dosu-chat-badge.svg)](https://app.dosu.dev/cdda13d9-dd27-4d31-b09a-5d8bec92de21/ask?utm_source=github)&nbsp;[![Open in Cursor](https://dosu.dev/dosu-in-cursor.svg)](https://cursor.com/link/prompt?text=The%20generic%20OAuth%20provider%20for%20Microsoft%20Entra%20ID%20in%20Better%20Auth%20fetches%20user%20info%20from%20the%20Microsoft%20Graph%20userinfo%20endpoint%20using%20the%20access%20token%2C%20which%20only%20maps%20fields%20like%20%60name%60%2C%20%60given_name%60%2C%20and%20%60family_name%60.%20This%20causes%20issues%20for%20personal%20Microsoft%20accounts%2C%20which%20return%20%60givenname%60%20and%20%60familyname%60%20instead%2C%20resulting%20in%20missing%20names%20and%20errors.%20There%E2%80%99s%20no%20documented%20reason%20in%20the%20code%20for%20why%20the%20generic%20provider%20doesn%E2%80%99t%20use%20the%20ID%20token%20like%20the%20social%20provider%20does%2C%20but%20this%20is%20the%20root%20cause%20of%20the%20inconsistency%20you%E2%80%99re%20seeing%C2%A0%5Bcitation%5D%28https%3A//github.com/better-auth/better-auth/blob/583f12fb7db38681ee882d219ce3895faa4a6976/packages/better-auth/src/plugins/generic-oauth/providers/microsoft-entra-id.ts%23L54-L86%29.%0A%0AA%20practical%20workaround%20is%20to%20override%20the%20%60getUserInfo%60%20method%20in%20your%20provider%20config%20to%20decode%20the%20ID%20token%20and%20normalize%20the%20fields%20yourself%2C%20similar%20to%20how%20the%20social%20provider%20works%C2%A0%5Bcitation%5D%28https%3A//github.com/better-auth/better-auth/blob/583f12fb7db38681ee882d219ce3895faa4a6976/packages/core/src/social-providers/microsoft-entra-id.ts%23L116-L236%29.%20Here%E2%80%99s%20a%20sample%20approach%3A%0A%0A%60%60%60typescript%0Aimport%20%7B%20decodeJwt%20%7D%20from%20%22jose%22%3B%0A%0AgetUserInfo%3A%20async%20%28token%29%20%3D%3E%20%7B%0A%20%20if%20%28%21token.idToken%29%20return%20null%3B%0A%20%20const%20profile%20%3D%20decodeJwt%28token.idToken%29%3B%0A%20%20return%20%7B%0A%20%20%20%20user%3A%20%7B%0A%20%20%20%20%20%20id%3A%20profile.sub%2C%0A%20%20%20%20%20%20name%3A%0A%20%20%20%20%20%20%20%20profile.name%20%7C%7C%0A%20%20%20%20%20%20%20%20%5Bprofile.given_name%20%7C%7C%20profile.givenname%2C%20profile.family_name%20%7C%7C%20profile.familyname%5D%0A%20%20%20%20%20%20%20%20%20%20.filter%28Boolean%29%0A%20%20%20%20%20%20%20%20%20%20.join%28%22%20%22%29%20%7C%7C%0A%20%20%20%20%20%20%20%20undefined%2C%0A%20%20%20%20%20%20email%3A%20profile.email%20%7C%7C%20profile.preferred_username%2C%0A%20%20%20%20%20%20image%3A%20profile.picture%2C%0A%20%20%20%20%20%20emailVerified%3A%20profile.email_verified%20%3F%3F%20false%2C%0A%20%20%20%20%7D%2C%0A%20%20%20%20data%3A%20profile%2C%0A%20%20%7D%3B%0A%7D%0A%60%60%60%0A%0AThis%20will%20ensure%20both%20personal%20and%20work%20accounts%20are%20handled%20consistently.%20If%20you%20need%20ID%20token%20verification%20%28not%20just%20decoding%29%2C%20you%E2%80%99ll%20need%20to%20implement%20that%20manually%2C%20as%20it%E2%80%99s%20not%20currently%20supported%20for%20Microsoft%20providers%20in%20Better%20Auth%C2%A0%5Bcitation%5D%28https%3A//github.com/better-auth/better-auth/issues/7776%29.%0A%0ARecent%20updates%20have%20improved%20type%20definitions%20for%20the%20social%20provider%2C%20but%20the%20generic%20OAuth%20provider%20hasn%E2%80%99t%20been%20updated%20to%20address%20this%20mapping%20issue%20yet%C2%A0%5Bcitation%5D%28https%3A//github.com/better-auth/better-auth/pull/3806%29.%20There%E2%80%99s%20ongoing%20discussion%20about%20improving%20normalization%20and%20documentation%2C%20but%20for%20now%2C%20overriding%20%60getUserInfo%60%20is%20the%20recommended%20solution.)&nbsp;[![Join Discord](https://img.shields.io/badge/join-5865F2?logo=discord&logoColor=white&label=)](https://go.dosu.dev/discord-bot)&nbsp;[![Share on X](https://img.shields.io/badge/X-share-black)](https://twitter.com/intent/tweet?text=%40dosu_ai%20helped%20me%20solve%20this%20issue!&url=https%3A//github.com/better-auth/better-auth/issues/7787)
Author
Owner

@bytaesu commented on GitHub (Feb 4, 2026):

https://learn.microsoft.com/en-us/entra/identity-platform/userinfo#userinfo-response
https://learn.microsoft.com/en-us/entra/identity-platform/optional-claims-reference#v20-specific-optional-claims-set

Hi @EjsenKirie,

The official docs use snake_case.
Do I have any reference I can check?

<!-- gh-comment-id:3847921626 --> @bytaesu commented on GitHub (Feb 4, 2026): > https://learn.microsoft.com/en-us/entra/identity-platform/userinfo#userinfo-response > https://learn.microsoft.com/en-us/entra/identity-platform/optional-claims-reference#v20-specific-optional-claims-set Hi @EjsenKirie, The official docs use snake_case. Do I have any reference I can check?
Author
Owner

@EjsenKirie commented on GitHub (Feb 5, 2026):

https://learn.microsoft.com/en-us/entra/identity-platform/userinfo#userinfo-response
https://learn.microsoft.com/en-us/entra/identity-platform/optional-claims-reference#v20-specific-optional-claims-set

Hi @EjsenKirie,

The official docs use snake_case. Do I have any reference I can check?

Hi @bytaesu! Thanks for the reply!

That is strange!

I think you should be able to confirm the behavior by utilzing the graph-explorer (https://developer.microsoft.com/en-us/graph/graph-explorer) and run a query against /oidc/userinfo
I have tested with both a hotmail.com and outlook.com account

<!-- gh-comment-id:3853996706 --> @EjsenKirie commented on GitHub (Feb 5, 2026): > > https://learn.microsoft.com/en-us/entra/identity-platform/userinfo#userinfo-response > > https://learn.microsoft.com/en-us/entra/identity-platform/optional-claims-reference#v20-specific-optional-claims-set > > Hi [@EjsenKirie](https://github.com/EjsenKirie), > > The official docs use snake_case. Do I have any reference I can check? Hi @bytaesu! Thanks for the reply! That is strange! I think you should be able to confirm the behavior by utilzing the graph-explorer (https://developer.microsoft.com/en-us/graph/graph-explorer) and run a query against `/oidc/userinfo` I have tested with both a `hotmail.com` and `outlook.com` account
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: github-starred/better-auth#10904