{"record":{"id":"1aab6ee977cc5d3b","repo":"AdguardTeam/AdGuardHome","slug":"auth-blocked-for-s","errorCode":null,"errorMessage":"auth: blocked for %s","messagePattern":"auth: blocked for (.+?)","errorType":"http","errorClass":null,"httpStatus":429,"severity":"warning","filePath":"internal/home/authhttp.go","lineNumber":142,"sourceCode":"\tif remoteIPStr, err = netutil.SplitHost(r.RemoteAddr); err != nil {\n\t\tweb.writeErrorWithIP(\n\t\t\tctx,\n\t\t\tfmt.Errorf(\"auth: getting remote address: %w\", err),\n\t\t\tr,\n\t\t\tw,\n\t\t\thttp.StatusBadRequest,\n\t\t\tr.RemoteAddr,\n\t\t)\n\n\t\treturn\n\t}\n\n\tif rateLimiter := web.auth.rateLimiter; rateLimiter != nil {\n\t\tif left := rateLimiter.check(remoteIPStr); left > 0 {\n\t\t\tw.Header().Set(httphdr.RetryAfter, strconv.Itoa(int(left.Seconds())))\n\t\t\tweb.writeErrorWithIP(\n\t\t\t\tctx,\n\t\t\t\tfmt.Errorf(\"auth: blocked for %s\", left),\n\t\t\t\tr,\n\t\t\t\tw,\n\t\t\t\thttp.StatusTooManyRequests,\n\t\t\t\tremoteIPStr,\n\t\t\t)\n\n\t\t\treturn\n\t\t}\n\t}\n\n\tip, err := realIP(r)\n\tif err != nil {\n\t\tweb.logger.ErrorContext(\n\t\t\tctx,\n\t\t\t\"getting real ip\",\n\t\t\t\"remote_ip\", remoteIPStr,\n\t\t\tslogutil.KeyError, err,\n\t\t)","sourceCodeStart":124,"sourceCodeEnd":160,"githubUrl":"https://github.com/AdguardTeam/AdGuardHome/blob/b41aefbe51c8dde65e2c50f093996afa0502edf9/internal/home/authhttp.go#L124-L160","documentation":"Returned by the login HTTP handler when the per-IP rate limiter has blocked further login attempts. The client has exceeded the allowed number of failed authentications within the window, and the retry delay (with Retry-After header) is embedded in the message.","triggerScenarios":"POST /login (handleLogin) from an IP that recently made too many attempts; web.auth.rateLimiter.check(remoteIPStr) returns a non-zero remaining block duration.","commonSituations":"Repeated wrong passwords, scripted/automated logins, several users behind one NAT/proxy IP, or testing login flows in a tight loop.","solutions":["Wait for the block to expire (the Retry-After header gives exact seconds)","Fix the credential or auth backend causing repeated failures","Ensure the correct X-Forwarded-For/trusted proxy config so NATed users aren't aggregated into one IP","Increase or tune the rate limiter limits if legitimate traffic is being blocked"],"exampleFix":"// before: hammering login in a loop\nfor pw in passwords: login(pw)\n// after: honor Retry-After\nresp = login(pw)\nif resp.status == 429: time.sleep(int(resp.headers['Retry-After']))","handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"// Check HTTP 429 and Retry-After before retrying login\nif resp.StatusCode == http.StatusTooManyRequests {\n    wait, _ := strconv.Atoi(resp.Header.Get(\"Retry-After\"))\n    time.Sleep(time.Duration(wait) * time.Second)\n}","preventionTips":["Cache session cookies/tokens instead of re-authenticating on every request","Use exponential backoff on 401/429 responses","Read the Retry-After header before any retry"],"tags":["auth","rate-limit","http","login"],"backgroundTag":"http-rate-limit-exceeded","analyzedSha":"b41aefbe51c8dde65e2c50f093996afa0502edf9","analyzedAt":"2026-08-27T04:57:55.097Z","schemaVersion":2},"datasetVersion":"2026-08-27T08:17:20.692Z"}