SG SealGrid Athena Docs

Login Rate Limiting & Brute-Force Protection

Athena guards the sign-in page with several independent layers of throttling so that automated password guessing is slowed to a crawl and repeat offenders are cut off. This page explains each layer — the connection-level request limiter on the login endpoint, the per-IP request limit with auto-ban, the per-account lockout and hard lock, and the growing delay between attempts — the order they fire in, the appsettings.json keys and defaults that tune them, how they behave when Athena sits behind a reverse proxy, and how to watch for an attack in the audit trail.

On by default — nothing to switch on

Every protection below is active out of the box with sensible defaults. You only need to touch the settings on this page if you want to make them stricter (or, rarely, looser). The two account-lockout values are also editable from the console — see Security Settings. The remaining values live in the server configuration file described here.

The layers, in order#

A single sign-in request passes through the checks below from the outside in. The first one that trips stops the request, so an attacker never gets to spend attempts against the layers further down.

#ProtectionScoped toTrigger (default)Effect
1 Connection request limiter The login endpoint, per source connection 20 requests / 60 s Excess requests are refused with 429 Too Many Requests and a Retry-After: 60 header, before any credentials are checked.
2 Per-IP request limit Each client IP address 10 sign-in requests / minute 429 Too Many Requests, and the IP is auto-banned for 30 minutes.
3 Progressive delay Each account Every failed sign-in A growing pause before the next attempt is accepted — 1s, 2s, 4s, 8s, capped at 16s.
4 Temporary lockout Each account 5 failed sign-ins The account is locked for 15 minutes, then clears itself automatically.
5 Hard lock Each account 30 failed sign-ins The account stays locked until an operator unlocks it — it does not clear on its own.

Layers 1 and 2 are request-rate limits: they care about how many requests arrive, regardless of whether the password was right. Layers 3–5 are account counters: they respond to how many of those attempts failed. Together they blunt both a fast flood from one source and a slow, patient guess against one account.

1. Connection request limiter#

The outermost guard is a fixed-window request limiter that applies only to the login endpoint (POST api/auth/login). It counts requests per source connection and, once the limit is exceeded within the window, immediately answers 429 Too Many Requests with a Retry-After: 60 header — the request never reaches the credential check. Because it runs at the very front of the request pipeline, it is the cheapest possible way to shed a flood of login traffic.

Key (under Security:ConnectionRateLimit)Environment variableDefaultWhat it does
PermitLimitSecurity__ConnectionRateLimit__PermitLimit20Login requests allowed from one connection per window.
WindowSecondsSecurity__ConnectionRateLimit__WindowSeconds60Length of the fixed window, in seconds.
// appsettings.json — allow at most 20 login requests per minute per connection
"Security": {
  "ConnectionRateLimit": {
    "PermitLimit": 20,
    "WindowSeconds": 60
  }
}
Only the login endpoint is limited

This limiter is scoped to POST api/auth/login only; every other API and console request passes through untouched. Changing PermitLimit or WindowSeconds is read from the configuration file, so a change takes effect the next time the server starts.

2. Per-IP request limit & auto-ban#

Behind the connection limiter, Athena also tracks sign-in requests per client IP address. When a single IP sends more than the allowed number of sign-in requests in a minute, further requests are refused with 429 Too Many Requests and that IP is automatically banned for 30 minutes. The ban is recorded in the audit trail.

Key (under Security)Environment variableDefaultWhat it does
MaxRequestsPerMinutePerIpSecurity__MaxRequestsPerMinutePerIp10Sign-in requests allowed from one IP per minute before the IP is rate-limited and auto-banned.

An operator can also ban an IP address on demand, or lift a ban, using the localhost-only recovery endpoints described on the Emergency Recovery page. Bans are held in the server's memory, so restarting the server clears every active IP ban and every account lockout at once.

3. Progressive delay#

Each time a sign-in fails for an account, the next attempt for that account is held back by a short, growing delay before it is even evaluated: roughly 1 second after the first failure, then 2, 4, 8, and capped at 16 seconds. A legitimate user who mistypes a password once or twice barely notices, but an automated guesser is throttled to a handful of tries per minute.

4. Temporary account lockout#

After a run of consecutive failures, the account is locked for a fixed period and then unlocks itself. These are the two values you can also set from Settings → Security in the console; see Security Settings → Account lockout.

Key (under Security)Console settingDefaultWhat it does
MaxFailedLoginAttemptsMax Failed Attempts5Consecutive failed sign-ins before the account is temporarily locked.
LockoutDurationMinutesLockout Duration (minutes)15How long the account stays locked before it unlocks automatically.
The sign-in error never reveals the reason

Whether a password was simply wrong, the account is temporarily locked, or the account is hard locked, the sign-in page returns the same generic error. This is deliberate: it stops an attacker from learning whether a username exists or which accounts are worth targeting. The specific reason is recorded in the audit trail, where you can see it.

5. Hard lock#

If failures against one account keep piling up well past the temporary-lockout threshold, the account is hard locked. Unlike a temporary lockout, a hard lock does not clear on its own — it stays in place until an operator unlocks the account. This is the case the Emergency Recovery tools exist for.

Key (under Security)Environment variableDefaultWhat it does
HardLockThresholdSecurity__HardLockThreshold30Failed sign-ins for one account before it is hard locked and requires a manual unlock.

To clear a hard lock, an Admin can unlock the account from the console, or — if every admin is locked out — use the localhost-only break-glass unlock from the server host. Both paths, along with the manual IP ban, are documented on the Emergency Recovery page.

Behind a reverse proxy#

If you publish Athena through a reverse proxy or load balancer (for example HAProxy or nginx), the two request-rate limiters see client addresses differently, and it is worth understanding why:

Watching for an attack#

Every sign-in outcome is written to the audit trail. A failed attempt is recorded as a LoginFailure event at Warning severity, capturing the username tried and the source IP address; a rate-limited or auto-banned request is recorded too. A successful sign-in is a LoginSuccess event at Information severity. See the Audit Event Types Reference for the full list.

A sudden burst of LoginFailure events — especially many usernames from one IP, or one username from many IPs — is the signature of a brute-force attempt. You can pull them from the PowerShell module:

# Connect as an Admin
Connect-Athena -Server "athena.contoso.com"

# Failed sign-ins in the last 24 hours, newest first
Get-AthenaAudit -EventType "LoginFailure" |
  Sort-Object Timestamp -Descending |
  Select-Object Timestamp, Username, IpAddress, Description

If you forward the audit trail to a SIEM, alert on a spike of LoginFailure events — see Audit Forwarding to SIEM. When you spot an offending address, ban it or clear an affected account from the Emergency Recovery page.

Tuning notes#