fix(web): check guild membership on the OAuth endpoint, not the bot one
The login gate called GET /guilds/{guild}/members/{user} — the Guild
resource's Get Guild Member, which wants a Bot token and the application
present in the guild. Handed a user Bearer token it answers 401, which
discordMember reports as an error, so every sign-in rendered "Discord
sign-in is unavailable right now" and nobody could get in.
The endpoint guilds.members.read actually grants is Get Current User Guild
Member, GET /users/@me/guilds/{guild}/member. Same single-guild question,
same privacy property, and it takes the token we hold. #18 flagged this as
verified from Discord's documentation but never from a live flow; it was
wrong.
The stub mirrored the implementation, so the suite could not see it. It now
serves the OAuth path and answers the bot path 401 the way Discord does —
without that, a regression falls through to 404 and reads as an ordinary
"not a member" refusal instead of failing.
This commit is contained in:
+10
-3
@@ -103,7 +103,13 @@ func newDiscordStub(t *testing.T) (*discordStub, *httptest.Server) {
|
||||
if status == http.StatusOK {
|
||||
fmt.Fprintf(w, `{"id":%q,"username":"owner"}`, st.ownerID)
|
||||
}
|
||||
// Discord answers the bot endpoint with 401 for a user Bearer token.
|
||||
// Standing in for that keeps a regression onto it loud: without this
|
||||
// the request would fall through to 404 and read as "not a member",
|
||||
// which is a refusal the caller treats as ordinary.
|
||||
case strings.HasPrefix(r.URL.Path, "/guilds/"):
|
||||
w.WriteHeader(http.StatusUnauthorized)
|
||||
case strings.HasPrefix(r.URL.Path, "/users/@me/guilds/"):
|
||||
st.memberPaths = append(st.memberPaths, r.URL.Path)
|
||||
st.memberAuth = append(st.memberAuth, r.Header.Get("Authorization"))
|
||||
status := st.memberStatus
|
||||
@@ -299,12 +305,13 @@ func TestDiscordLoginFullFlow(t *testing.T) {
|
||||
}
|
||||
|
||||
// Identity and membership were fetched with the exchanged token, and the
|
||||
// membership check used the single-guild endpoint.
|
||||
// membership check used the OAuth single-guild endpoint — the one
|
||||
// guilds.members.read grants, not its bot-token twin.
|
||||
if len(stub.userAuth) != 1 || stub.userAuth[0] != "Bearer tok-1" {
|
||||
t.Fatalf("users/@me Authorization = %v, want [Bearer tok-1]", stub.userAuth)
|
||||
}
|
||||
if len(stub.memberPaths) != 1 || stub.memberPaths[0] != "/guilds/guild-1/members/owner-snowflake" {
|
||||
t.Fatalf("member requests = %v, want the single-guild endpoint", stub.memberPaths)
|
||||
if len(stub.memberPaths) != 1 || stub.memberPaths[0] != "/users/@me/guilds/guild-1/member" {
|
||||
t.Fatalf("member requests = %v, want the OAuth single-guild endpoint", stub.memberPaths)
|
||||
}
|
||||
if len(stub.memberAuth) != 1 || stub.memberAuth[0] != "Bearer tok-1" {
|
||||
t.Fatalf("member Authorization = %v, want [Bearer tok-1]", stub.memberAuth)
|
||||
|
||||
Reference in New Issue
Block a user