Bound pending flow states
CI / ci (push) Successful in 9m31s

The login route is unauthenticated, so its pending states could grow
without limit and every Add scanned them all. Expired states now leave
from the front of an add-ordered queue, and Add refuses a new flow with
ErrTooManyPending once 10000 are pending; login answers 503. Both flows
record the state before setting the cookie.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-11 01:40:18 -04:00
co-authored by Claude Opus 5.5
parent 0dccf87b06
commit 0f7f8014f8
4 changed files with 77 additions and 8 deletions
+5 -1
View File
@@ -253,12 +253,16 @@ func (a *Auth) login(w http.ResponseWriter, r *http.Request) {
Return: returnTo,
}
now := time.Now()
if err := a.pending.Add(state.State, now); err != nil {
a.logger.WarnContext(r.Context(), "login refused", "error", err)
http.Error(w, "too many sign-ins in progress; try again later", http.StatusServiceUnavailable)
return
}
if err := a.cookie.set(w, state, now); err != nil {
a.logger.ErrorContext(r.Context(), "set login cookie", "error", err)
http.Error(w, "internal error", http.StatusInternalServerError)
return
}
a.pending.Add(state.State, now)
http.Redirect(w, r, a.oauth.AuthCodeURL(state.State,
oidc.Nonce(state.Nonce),
oauth2.S256ChallengeOption(state.Verifier),