Skip to content

fix(auth): take the member email from the UserInfo endpoint - #2989

Merged
mroderick merged 2 commits into
codebar:fix/id-token-missing-email-guardfrom
mroderick:fix/userinfo-email
Oct 7, 2026
Merged

mroderick merged 2 commits into
codebar:fix/id-token-missing-email-guardfrom
mroderick:fix/userinfo-email

Conversation

@mroderick

Copy link
Copy Markdown
Collaborator

Sign-in now resolves the member email and name from the OIDC UserInfo response instead of the id_token, so it keeps working with better-auth 1.7's sparse id_tokens and never keys a member on sub.

  • Email comes from userinfo only; a blank one fails the callback with :missing_email, so no member is created from a non-email id. The id_token email claim is not consulted.
  • A failed userinfo request fails with :userinfo_failed, so a degraded auth app is distinguishable from a member without an email. Common Net::HTTP and OpenSSL transport errors are rescued into that path, and a non-object userinfo body counts as a request failure.
  • Name falls back from userinfo to the id_token name, then to the email address.
  • The id_token stays the source of sub and github_id in extra.raw_info; the controller's returning-member resolution is unchanged.

This continues the :missing_email guard in the base branch: the guard stays as the integrity floor, and the email source moves to userinfo. Cleaning up members already keyed on better-auth user ids remains follow-up work. The auth app needs no claims code for this, so codebar/auth#83 can close.

Review notes

Focus on the failure semantics and the email precedence. Userinfo is the only email source, even when the id_token carries one: a blank email there fails :missing_email, a failed request fails :userinfo_failed. There is no fallback to the id_token email.

Deliberately not done: a sub-match guard between the id_token and the userinfo response (better-auth re-pins sub), checking email_verified (the auth app's verification policy is trusted as before), and shortening the userinfo timeout or capping concurrent callbacks under a degraded provider.

Related: #2986, codebar/auth#83

better-auth 1.7 stopped putting user-record claims in the id_token and serves them from the UserInfo endpoint instead (OIDC Core section 5.4), so the callback now fetches GET /api/auth/oauth2/userinfo with the access token after the code exchange and resolves identity from that response.

Email comes from userinfo only; a blank one fails the callback with :missing_email, keeping the previous commit's guard as the integrity floor so no member is ever keyed on `sub`. Name falls back from userinfo to the id_token name, then to the email address. The id_token remains the source of `sub` and `github_id` in `extra.raw_info`.
A userinfo transport failure, non-200 response, or malformed body now fails the callback with :userinfo_failed instead of :missing_email, so a degraded auth app is distinguishable from a member without an email. The rescue list gains the common Net::HTTP and OpenSSL transport errors (connection reset, unreachable host, SSL failure) that previously escaped to :unknown_error, and a valid-JSON non-object body counts as a request failure instead of raising.
@mroderick
mroderick deleted the branch codebar:fix/id-token-missing-email-guard October 7, 2026 16:19
@mroderick mroderick closed this Oct 7, 2026
@mroderick mroderick reopened this Oct 7, 2026
@mroderick
mroderick merged commit b8c3c04 into codebar:fix/id-token-missing-email-guard Oct 7, 2026
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.

2 participants