Skip to content

fix(oauth-provider): omit given_name and family_name when the user has no name - #11201

Open
SibteProf wants to merge 1 commit into
better-auth:mainfrom
SibteProf:fix/oauth-provider-null-display-name
Open

fix(oauth-provider): omit given_name and family_name when the user has no name#11201
SibteProf wants to merge 1 commit into
better-auth:mainfrom
SibteProf:fix/oauth-provider-null-display-name

Conversation

@SibteProf

@SibteProf SibteProf commented Sep 7, 2026

Copy link
Copy Markdown

Closes #11193

The bug

splitDisplayName in packages/oauth-provider/src/standard-claims.ts takes a plain string and immediately calls name.split(" "). Resolving given_name or family_name for a user whose stored name is null throws a TypeError out of the claim resolver, surfacing as 500 from /userinfo, and from the token endpoint whenever an ID token is issued. Any client requesting the profile scope for such a user hits it.

Why this is a contract violation, not just bad data

userSchema types name as z.string(), so the null does not come from the type contract. It comes from how this module already treats the value:

name:        { scope: "profile", resolve: (user) => user.name ?? undefined },              // guards
given_name:  { scope: "profile", resolve: (user) => splitDisplayName(user.name).given },   // throws
family_name: { scope: "profile", resolve: (user) => splitDisplayName(user.name).family },  // throws

userNormalClaims in userinfo.ts does the same for the subject (sub: user.id ?? undefined). So the module already treats these fields as runtime-nullable — three claims resolve a missing value to an absent claim, and two dereference it one line later. That inconsistency is the defect: a claim the provider cannot resolve should be omitted, not fail the entire response including the claims that did resolve.

The change

splitDisplayName now accepts a nullish name and returns no claims for it. It is a module-private helper, so no exported type changes and User["name"] stays z.string() — the runtime guard is not being used to loosen the public type contract.

Testing

New packages/oauth-provider/src/standard-claims.test.ts exercises the resolvers directly: two-part and multi-part names, single word, blank, null, and undefined. The null and undefined cases fail on main with the reported TypeError and pass with this change.

  • vitest packages/oauth-provider — 42 files, 948 tests passing
  • pnpm typecheck — passing

AI assistance

Disclosed per CONTRIBUTING: this change was AI-assisted (Claude Code) — the investigation, patch and tests were produced with it. I have reviewed the full diff myself and verified it locally by running the commands above. Happy to discuss any of it in review.


Summary by cubic

Fixes the OAuth provider so given_name and family_name claims are omitted for users with no name instead of failing the request. Previously, requesting the profile scope for such a user returned 500 from /userinfo and from the token endpoint when an ID token was issued.

  • splitDisplayName now accepts a nullish name and returns no claims.
  • Added tests covering two-part, multi-part, single-word, blank, null, and undefined names.

Written for commit 2a264c8. Summary will update on new commits.

Review in cubic

…s no name

splitDisplayName took a plain string and called name.split(" ") on it. The
name column is nullable in practice, so resolving the given_name or
family_name claim for a user without a name threw a TypeError out of the
claim resolver, returning 500 from /userinfo and from the token endpoint
whenever an ID token was issued.

The adjacent name claim already resolves the same value with `?? undefined`,
so the null is expected in this module; only the split was unguarded. Accept
a nullish name and return no claims for it, which leaves both claims absent
rather than failing the whole response.

Closes better-auth#11193
@SibteProf
SibteProf requested review from a team as code owners September 7, 2026 13:41
@SibteProf
SibteProf requested review from gustavovalverde and removed request for a team September 7, 2026 13:41
@vercel

vercel Bot commented Sep 7, 2026

Copy link
Copy Markdown

@SibteProf is attempting to deploy a commit to the better-auth Team on Vercel.

A member of the Team first needs to authorize it.

@better-release better-release Bot added the identity OAuth/OIDC provider, device flow label Sep 7, 2026
@greptile-apps

greptile-apps Bot commented Sep 7, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR prevents OAuth profile-claim resolution from throwing when a user has no display name.

  • Accepts nullish display names in the module-private splitting helper.
  • Omits unresolved given_name and family_name claims.
  • Adds direct resolver coverage for ordinary, single-word, blank, null, and undefined names.

Confidence Score: 5/5

The PR appears safe to merge and fixes the null-name failure without weakening OAuth or OIDC security boundaries.

The nullish guard converts an otherwise throwing profile-claim resolution into absent optional claims, and the added tests cover the affected resolver behavior without exposing a regression.

Reviews (1): Last reviewed commit: "fix(oauth-provider): omit given_name and..." | Re-trigger Greptile

@cubic-dev-ai cubic-dev-ai Bot 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.

No issues found across 3 files

Re-trigger cubic

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

Labels

identity OAuth/OIDC provider, device flow

Projects

None yet

Development

Successfully merging this pull request may close these issues.

oauth-provider: userinfo/id_token 500s when user.name is null — splitDisplayName splits unguarded

1 participant