Skip to content

fix(discord): always include identify scope (#414)#642

Open
yabanci wants to merge 1 commit into
markbates:masterfrom
yabanci:fix/discord-identify-scope
Open

fix(discord): always include identify scope (#414)#642
yabanci wants to merge 1 commit into
markbates:masterfrom
yabanci:fix/discord-identify-scope

Conversation

@yabanci
Copy link
Copy Markdown

@yabanci yabanci commented May 17, 2026

What

Closes #414.

providers/discord/discord.go:newConfig currently drops ScopeIdentify whenever the caller passes any custom scope:

if len(scopes) > 0 {
    for _, scope := range scopes {
        c.Scopes = append(c.Scopes, scope)
    }
} else {
    c.Scopes = []string{ScopeIdentify}
}

So calling discord.New(k, s, cb, "email") yields Scopes: ["email"], which Discord rejects with 401 from /users/@me. The reporter (@tardisx) hit this exact path.

Discord's docs are explicit: identify is the scope that gates /users/@me itself; email only enriches the response. The existing constant in this file even spells it out:

// ScopeIdentify allows /users/@me without email
// ScopeEmail enables /users/@me to return an email

Change

Always include ScopeIdentify first, then append user scopes while filtering out a duplicate identify:

Scopes: []string{ScopeIdentify},
...
for _, scope := range scopes {
    if scope != ScopeIdentify {
        c.Scopes = append(c.Scopes, scope)
    }
}

Backward compatibility

  • Callers passing no scopes: unchanged — [identify].
  • Callers passing [identify, ...]: unchanged — order preserved, no duplication.
  • Callers passing scopes without identify (e.g. [email]): now [identify, email] instead of [email]. Their previously-broken FetchUser call now succeeds. The only behavioural difference is that Discord's consent screen will list identify — which is correct, since the app was already trying to read user info.

Tests

Added Test_DefaultScopeAlwaysIncludesIdentify — table-driven, four cases:

name input scopes expected config.Scopes
no scopes nil [identify]
email only [email] [identify, email]
identify explicit (no dupe) [identify, email] [identify, email]
multiple custom [email, connections, guilds] [identify, email, connections, guilds]

Verified the new test fails on master (cases 2 and 4 explicitly miss identify) and passes with the fix applied. go test ./... is green across all 50+ providers; go vet ./... is clean.

The discord provider's newConfig dropped ScopeIdentify whenever the
caller passed any custom scope. Discord's /users/@me endpoint requires
the identify scope -- other scopes (email, connections, guilds) only
enrich the response, they don't grant access on their own. So callers
that requested e.g. just 'email' got a 401 from FetchUser.

Always include ScopeIdentify in the OAuth2 scope list and skip it when
appending user-supplied scopes to avoid duplicating it. Added a
table-driven regression test covering: no scopes, email-only,
explicit identify (no dupe), and multiple custom scopes.
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.

discord provider requires "identify" scope

1 participant