AI Implementation feature(873): Landing Page and Login/Register Modal 1.01 (#13)
This commit was merged in pull request #13.
This commit is contained in:
+30
-17
@@ -1,7 +1,7 @@
|
||||
---
|
||||
type: api
|
||||
title: Auth Endpoints
|
||||
description: Login, refresh, logout, public self-registration, CSRF, and first-admin registration.
|
||||
description: Login, refresh, logout, public self-registration, CSRF, first-admin registration, and registration throttling.
|
||||
tags: [api, auth, login, register, refresh, csrf]
|
||||
timestamp: 2026-07-21T18:28:00Z
|
||||
---
|
||||
@@ -51,18 +51,27 @@ The refresh token is set as an `HttpOnly` cookie via `setRefreshCookie(res, sess
|
||||
| 400 | `WEAK_PASSWORD` | Argon2 policy rejects the password. |
|
||||
| 403 | `REGISTRATIONS_DISABLED`| `setting.registrationsEnabled !== 'true'`. |
|
||||
| 409 | `USERNAME_TAKEN` | A user with that username already exists. |
|
||||
| 429 | `RATE_LIMITED` | `RegistrationRateLimitService` blocked the IP. |
|
||||
| 429 | `RATE_LIMITED` | The per-IP registration limiter has reached 10 attempts in the rolling 60-second window. |
|
||||
|
||||
## Wiring
|
||||
|
||||
* `AuthService.registerPlayer(dto, ip)` runs inside a single
|
||||
`DataSource.transaction`:
|
||||
1. `RegistrationRateLimitService.isAllowed(ip)` check.
|
||||
* `AuthService.registerPlayer(dto, ip)` runs inside a single `DataSource.transaction`:
|
||||
1. `RegistrationRateLimitService.tryConsume(ip)` permits at most 10 attempts per IP in a rolling 60-second window.
|
||||
2. `SettingsService.get(SETTINGS_KEYS.REGISTRATIONS_ENABLED, 'false')` check.
|
||||
3. Username uniqueness lookup → `USERNAME_TAKEN` on collision.
|
||||
4. Argon2id hash + insert `UserEntity({ role: 'player', status: 'enabled' })`.
|
||||
5. `RegistrationRateLimitService.record(ip)`.
|
||||
6. `mintSession(manager, user)` → access JWT + refresh row.
|
||||
5. `mintSession(manager, user)` → access JWT + refresh row.
|
||||
* `AuthService.registerFirstAdmin(username, password, ip)` uses the same limiter before checking whether an administrator already exists.
|
||||
* The limiter is an in-memory Nest provider in `backend/src/common/services/registration-rate-limit.service.ts`; counters are process-local and reset when the API process restarts.
|
||||
|
||||
# Key Files
|
||||
|
||||
| File | Responsibility |
|
||||
|------|----------------|
|
||||
| `backend/src/modules/auth/auth.service.ts` | Validates registration policy, applies the limiter, creates users, and mints sessions. |
|
||||
| `backend/src/common/services/registration-rate-limit.service.ts` | Tracks timestamps and enforces the 10-per-minute per-IP limit. |
|
||||
| `backend/src/modules/auth/auth.controller.ts` | Exposes public registration and authentication routes. |
|
||||
| `backend/src/modules/auth/dto/auth.dto.ts` | Validates registration request fields. |
|
||||
|
||||
# Frontend consumer
|
||||
|
||||
@@ -70,18 +79,22 @@ The refresh token is set as an `HttpOnly` cookie via `setRefreshCookie(res, sess
|
||||
`register()`. Both:
|
||||
|
||||
1. Call `ensureCsrf()` → `GET /api/v1/auth/csrf` to materialise the `csrf`
|
||||
cookie if it isn't set yet (failures are swallowed because the
|
||||
`CsrfMiddleware` will mint the cookie on the next response anyway).
|
||||
cookie if it isn't set yet.
|
||||
2. `POST` with `{ withCredentials: true, observe: 'response' }`.
|
||||
3. Return a discriminated union:
|
||||
* `{ ok: true, accessToken, expiresIn, user }` on success.
|
||||
* `{ ok: false, status, code, message }` on failure, built by the
|
||||
private `mapAuthError()` helper from the standard
|
||||
[error envelope](/api/rest-overview.md).
|
||||
3. Return success or the standard [error envelope](/api/rest-overview.md).
|
||||
|
||||
The `LandingComponent` (`frontend/src/app/features/landing/landing.component.ts`)
|
||||
consumes both methods and maps the `code` to user-facing copy via
|
||||
`buildLoginFailureMessage` (see [Landing Page](/guides/landing-page.md)).
|
||||
The `LandingComponent` consumes both methods and maps failures to user-facing
|
||||
copy (see [Landing Page](/guides/landing-page.md)).
|
||||
|
||||
# Examples
|
||||
|
||||
## Tester flow: registration rate limit
|
||||
|
||||
1. Enable registrations in the admin settings.
|
||||
2. Open the public registration form from the landing page.
|
||||
3. Submit attempts from the same client IP.
|
||||
4. The first 10 attempts are processed normally; the 11th within 60 seconds returns HTTP `429` with code `RATE_LIMITED`.
|
||||
5. After the rolling window expires, a new attempt is accepted if other requirements pass.
|
||||
|
||||
# See also
|
||||
|
||||
|
||||
Reference in New Issue
Block a user