init push

This commit is contained in:
2026-07-16 22:16:45 +07:00
commit 8b068bdb10
1021 changed files with 332816 additions and 0 deletions

91
docs/password-reset.md Normal file
View File

@@ -0,0 +1,91 @@
# Password Reset
## Endpoints
### `POST /api/v1/auth/forgot-password`
Request:
```json
{
"data": {
"type": "auth_forgot_password",
"attributes": {
"email": "user@example.com"
}
}
}
```
Response (`200` always for valid payload):
```json
{
"data": {
"type": "auth_forgot_password",
"attributes": {
"message": "If the account exists, a password reset link has been sent."
}
}
}
```
### `POST /api/v1/auth/reset-password`
Request:
```json
{
"data": {
"type": "auth_reset_password",
"attributes": {
"token": "<raw-token>",
"new_password": "StrongPassphrase123!",
"confirm_password": "StrongPassphrase123!"
}
}
}
```
Success response (`200`):
```json
{
"data": {
"type": "auth_reset_password",
"attributes": {
"message": "Password has been reset successfully. Please log in again."
}
}
}
```
Invalid/expired/used token response (`400`):
```json
{
"errors": [
{
"status": "400",
"title": "Invalid reset link",
"detail": "This reset link is invalid or expired."
}
]
}
```
## Environment Variables
- `AUTH_PASSWORD_RESET_URL` frontend reset page URL; backend appends `?token=...`
- `AUTH_PASSWORD_RESET_TTL` reset token TTL (default `20m`, enforced 15-30m range)
- `AUTH_FORGOT_PASSWORD_EMAIL_COOLDOWN` cooldown per email identifier (default `2m`)
- `AUTH_FORGOT_PASSWORD_MIN_DURATION` minimum forgot-password response duration (default `150ms`)
- `AUTH_FORGOT_PASSWORD_IP_RATE_MAX` per-IP max attempts in window (default `10`)
- `AUTH_FORGOT_PASSWORD_IP_RATE_WINDOW` per-IP window duration (default `15m`)
## Security Decisions
- Uses `crypto/rand` for reset token entropy.
- Stores only SHA-256 token hashes in DB (`password_reset_tokens.token_hash`).
- Raw token is only delivered via email link.
- Tokens are single-use (`used_at`) and expire (`expires_at`).
- New forgot-password request invalidates previous active reset tokens for that user.
- Successful reset invalidates all active reset tokens for the user.
- Successful reset revokes active sessions by incrementing the MySQL-backed user session version used in JWT claims.
- Forgot-password response is generic to prevent account enumeration.
- Forgot-password throttling is applied per IP and per email identifier.