| Refresh | Hashed in DB; remember-me ≈ 30 days, short session ≈ 24 hours |
| Browser cookies | `pargar_access` / `pargar_refresh` — `HttpOnly`, `SameSite=Lax`, `Secure` when `PUBLIC_URL` is https |
| Frontend storage | Only `user` in `localStorage` (`pargar.auth`); tokens are not persisted |
| API | `credentials: "include"`; optional Bearer for tests/clients |
| Logout | Revoke refresh + clear cookies |
Public password recovery (`/api/auth/recovery/*` and `/recovery`) is disabled for students (404). Resets are admin-only and require the target account’s security answer.
## Secrets
- Outside `DEV_MODE`, `Validate()` rejects values like `change-me` / `local-dev-only` and JWTs shorter than 32 characters.
- Local Helm: generate-once; production: `existingSecret` required.
-`ADMIN_PASSWORD` only bootstraps when the admin user is missing; restarts do not overwrite the password.
## Proxy and CORS
- Only peers in `TRUSTED_PROXY_CIDRS` are trusted for `X-Forwarded-*` / `X-Real-IP`.
- CORS: `FRONTEND_ORIGINS` + `PUBLIC_URL` with `AllowCredentials: true`.
`REGISTRATION_ENFORCE_IP` (default **false**) optionally limits one successful public/invite registration per client IP. Leave it off when the app sits behind NAT or shared egress and cannot see real client addresses. Enable only after the edge forwards trustworthy `X-Forwarded-For` / `X-Real-IP` via `TRUSTED_PROXY_CIDRS`.
`/api/health` is excluded from the global ceiling. Note: per-IP rate limits still use the peer/forwarded address — configure trusted proxies when you need per-client fairness behind NAT.