Skip to content

feat: opt-in github numeric user id, reject non-2xx user info - #301

Merged
umputun merged 5 commits into
masterfrom
feat/github-numeric-id
Jul 25, 2026
Merged

feat: opt-in github numeric user id, reject non-2xx user info#301
umputun merged 5 commits into
masterfrom
feat/github-numeric-id

Conversation

@umputun

@umputun umputun commented Jul 25, 2026

Copy link
Copy Markdown
Member

two changes, both applied to v1 and v2.

opt-in github user id from the numeric account id

the github provider derives the local user id from the login, github_<sha1(login)>. GitHub releases a username on rename or account deletion and anyone can claim it afterwards, so an id derived from login can be inherited by the next holder of the name. Every other oauth2 provider here already keys on an immutable subject: google on sub, the rest on id or id_str.

new provider.Params.GithubNumericID and Service.AddGithubProviderWithNumericID derive the id from the immutable numeric account id instead. Off by default, because switching the derivation changes the id of every existing github user, and apps that key records, roles or blocks on that id cannot remap them offline. The README documents the caveat and the migration cost.

the hashed input is domain separated with a gid: prefix. Without it the two id spaces overlap: github allows all-digit logins, so login 27385 and account id 27385 produce the same local id, and those are two different real accounts.

reject non-2xx user info responses

the oauth1 and oauth2 callback handlers checked only the transport error from the user info request, never the HTTP status. An error body carries no identity fields, so mapUser hashed empty values and every failed callback produced the same local id, github_ + sha1("") for github. A revoked token, a rate limit or a provider outage was enough to sign the caller in under that shared identity.

this affects all oauth2 providers and the oauth1 (twitter) path. Apple and telegram already checked their status codes.

umputun added 5 commits July 24, 2026 19:10
GitHub logins are released on rename or account removal and can be claimed
by someone else, so a local id derived from the login may be inherited by
the next holder of the name. Every other oauth2 provider here keys on an
immutable subject, github was the only one on a mutable field.

Add Params.GithubNumericID and Service.AddGithubProviderWithNumericID to
derive the id from the numeric account id instead. Off by default because
it changes the id of every existing github user, and records stored under
the old id cannot be remapped offline once a login is hashed.

The numeric id is read from the raw response body with a typed unmarshal.
data.Value is not usable for it, json numbers decode to float64 and format
as "1.345027e+06". A missing or zero id keeps the login-based value rather
than hashing an empty string.

Applied to both the v1 (provider/) and v2 (v2/provider/) module paths.
- [major] [provider/providers.go:70] numeric ids shared a hash namespace with logins, which may be all-digit; domain-separate the hashed input with a "gid:" prefix
- [major] [auth_test.go] AddGithubProviderWithNumericID had no test; add Service-level coverage plus the default-unchanged negative case
- [minor] [provider/providers.go:69] warn when the numeric id is unusable instead of falling back silently
- [minor] [provider/providers.go:52] default the logger in NewGithub, the mapUser closure captures p before initOauth2Handler defaults its own copy
- [minor] [provider/providers.go:65] comment claimed the login fallback was safe; state the recycling caveat instead
- [minor] [provider/oauth2.go:62] document the best-effort fallback on Params.GithubNumericID and the Service method
- [minor] [auth.go:389] add the advanced-configuration note the AddMicrosoftProvider godoc carries
- [minor] [README.md:749] use placeholders instead of the _example env vars, and name the direct-Params registration route

Applied to both the v1 and v2 module paths.
- [major] [README.md:752] the direct-Params recipe omitted AllowedRedirectHosts and L; AddCustomHandler registers the handler as-is, so a service that hardened AllowedRedirectHosts in Opts would silently lose redirect validation for the github provider
The oauth1 and oauth2 callback handlers checked only the transport error from
the user info request, never the HTTP status. An error body from the provider
carries no identity fields, so mapUser hashed empty values and every failed
callback produced the same local id, e.g. github_ + sha1("") for github. A
revoked token, a rate limit or a provider outage was enough to sign the caller
in under that shared identity.

Reject any non-2xx user info response before reading and mapping it. Affects
all oauth2 providers and the oauth1 (twitter) path. Apple and telegram already
checked their status codes.

Applied to both the v1 and v2 module paths.
The "with extra scopes" subtest redeclared r inside the closure, shadowing the
handler from the enclosing test. govet's shadow check is enabled and CI runs a
pinned golangci-lint, so this failed the lint job. Rename to withAttrs.

Applied to both the v1 and v2 module paths.
Copilot AI review requested due to automatic review settings July 25, 2026 01:03

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@coveralls

coveralls commented Jul 25, 2026

Copy link
Copy Markdown

Coverage Report for CI Build 30137641650

Coverage increased (+0.05%) to 85.492%

Details

  • Coverage increased (+0.05%) from the base build.
  • Patch coverage: 4 uncovered changes across 1 file (37 of 41 lines covered, 90.24%).
  • No coverage regressions found.

Uncovered Changes

File Changed Covered %
provider/oauth1.go 5 1 20.0%
Total (4 files) 41 37 90.24%

Coverage Regressions

No coverage regressions found.


Coverage Stats

Coverage Status
Relevant Lines: 3598
Covered Lines: 3076
Line Coverage: 85.49%
Coverage Strength: 8.51 hits per line

💛 - Coveralls

@umputun
umputun merged commit 8108402 into master Jul 25, 2026
9 checks passed
@umputun
umputun deleted the feat/github-numeric-id branch July 25, 2026 01:08
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.

3 participants