After LOGIN_MAX_FAILURES consecutive failed attempts from the same source IP within LOGIN_WINDOW_SECONDS, POST /api/v1/auth/token returns HTTP 429 with a Retry-After header for LOGIN_COOLDOWN_SECONDS. A successful login resets the counter. Trusted upstream proxy IPs/CIDRs can be declared via LOGIN_TRUSTED_PROXY_IPS so X-Forwarded-For is honoured correctly behind nginx ingress or similar reverse proxies. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
86 lines
1.8 KiB
Markdown
86 lines
1.8 KiB
Markdown
# API Contract: Authentication
|
|
|
|
## POST /api/v1/auth/token
|
|
|
|
Authenticates the owner and returns a JWT access token.
|
|
|
|
**This endpoint is modified by feature 009** to enforce brute-force protection.
|
|
All previous behaviour is preserved. One new response code (429) is added.
|
|
|
|
### Request
|
|
|
|
```
|
|
POST /api/v1/auth/token
|
|
Content-Type: application/json
|
|
```
|
|
|
|
```json
|
|
{
|
|
"username": "string",
|
|
"password": "string"
|
|
}
|
|
```
|
|
|
|
### Responses
|
|
|
|
#### 200 OK — Credentials accepted
|
|
|
|
```json
|
|
{
|
|
"access_token": "<jwt>",
|
|
"token_type": "bearer",
|
|
"expires_in": 86400
|
|
}
|
|
```
|
|
|
|
Side effect: resets the failure counter for the caller's IP address.
|
|
|
|
---
|
|
|
|
#### 401 Unauthorized — Credentials rejected
|
|
|
|
```json
|
|
{
|
|
"detail": "Invalid credentials",
|
|
"code": "invalid_credentials"
|
|
}
|
|
```
|
|
|
|
Side effect: increments the failure counter for the caller's IP address. If the
|
|
counter reaches `LOGIN_MAX_FAILURES`, subsequent requests from this IP will receive
|
|
429 until the cooldown expires.
|
|
|
|
---
|
|
|
|
#### 429 Too Many Requests — Source blocked after repeated failures
|
|
|
|
**This response is new in feature 009.**
|
|
|
|
```
|
|
HTTP/1.1 429 Too Many Requests
|
|
Retry-After: 900
|
|
Content-Type: application/json
|
|
```
|
|
|
|
```json
|
|
{
|
|
"detail": "Too many failed login attempts. Please try again later.",
|
|
"code": "login_rate_limited"
|
|
}
|
|
```
|
|
|
|
The `Retry-After` header value is the configured cooldown duration in seconds (default: 900).
|
|
It reflects the maximum possible wait, not the exact remaining lockout time.
|
|
|
|
No credentials are verified when this response is returned — the request is
|
|
rejected before authentication is attempted.
|
|
|
|
---
|
|
|
|
### Notes
|
|
|
|
- The failure counter is per source IP address (TCP peer, not forwarded headers).
|
|
- Threshold values (`LOGIN_MAX_FAILURES`, `LOGIN_WINDOW_SECONDS`, `LOGIN_COOLDOWN_SECONDS`)
|
|
are not disclosed in any response.
|
|
- Counters are in-memory and reset on process restart.
|