v1.0.10 légal item 2. The signup endpoint /api/v1/auth/register and
its frontend form now require a date of birth and refuse registrations
where the registrant would be < 16 years old at registration time.
Threshold rationale :
COPPA (US, < 13 forbidden) + RGPD strict (< 16 needs parental
consent in every EU member state at the highest interpretation).
16 is the conservative single cutoff that satisfies both regimes
without per-jurisdiction branching. If a future market needs a
different threshold, change MinRegistrationAgeYears in
internal/core/auth/service.go ; the frontend reads the same
constant so they stay aligned.
Backend changes
* dto.RegisterRequest gets a `Birthdate string` field, validated
`required,datetime=2006-01-02` so swaggo / orval emit the right
OpenAPI schema and the validator catches malformed values
before the handler even runs.
* AuthService.Register signature is now
(ctx, email, username, password, birthdate *time.Time). The
pointer lets internal seed paths / tests pass nil while the
public handler always supplies a parsed value.
* Age check uses a yearsBetween helper that handles the "anniversary
hasn't passed yet this year" case correctly (someone born
2008-05-01 is 16 on 2008+16-05-01, not on 2008+16-01-01).
* New sentinel auth.ErrUnderage ; handler maps it to 400 with a
friendly message ("You must be at least 16 years old to register")
so the SPA can render the right copy without parsing the message.
* 11 test call sites updated : test-only paths pass nil ; the
public-handler test (TestRegister_Success) and the in-package
handler test pass a fixture Birthdate "2000-01-15".
Frontend changes
* RegisterFormData type + zod schema in RegisterForm.tsx + initial
form state get a `birthdate` field.
* RegisterPageForm.tsx renders an `<AuthInput type="date">` with a
`max=` attr 16 years ago today (UX guard ; legal floor stays in
the API).
* useRegisterPage's validate() computes age client-side with the
same algorithm as backend ; emits localised errors
`birthdateRequired` / `birthdateInvalid` / `birthdateUnderage`
so the user gets immediate feedback.
* services/api/auth.ts RegisterRequest interface + register()
body include the new field.
Tests : `go test ./internal/core/auth ./internal/handlers -short`
passes ; `tsc --noEmit` clean ; `eslint src` 754 (baseline unchanged).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Item 1.4 — Register no longer issues an access+refresh token pair. The
prior flow set httpOnly cookies at register but the AuthMiddleware
refused them on every protected route until the user had verified
their email (`core/auth/service.go:527`). Users ended up with dead
credentials and a "logged in but locked out" UX. Register now returns
{user, verification_required: true, message} and the SPA's existing
"check your email" notice fires naturally.
Item 1.3 — `POST /auth/verify-email` reads the token from the
`X-Verify-Token` header in preference to the `?token=…` query param.
Query param logged a deprecation warning but stays accepted so emails
dispatched before this release still work. Headers don't leak through
proxy/CDN access logs that record URL but not headers.
Tests: 18 test files updated (sed `_, _, err :=` → `_, err :=` for the
new Register signature). `core/auth/handler_test.go` gets a
`registerVerifyLogin` helper for tests that exercise post-login flows
(refresh, logout). Two new E2E `@critical` specs lock in the defer-JWT
contract and the header read-path.
OpenAPI + orval regenerated to reflect the new RegisterResponse shape
and the verify-email header parameter.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- Created TwoFactorHandler with SetupTwoFactor, VerifyTwoFactor, DisableTwoFactor, GetTwoFactorStatus
- Added routes: POST /auth/2fa/setup, POST /auth/2fa/verify, POST /auth/2fa/disable, GET /auth/2fa/status
- Updated LoginResponse DTO to include requires_2fa flag
- Updated Login handler to check 2FA status and return requires_2fa flag when enabled
- Reused existing TwoFactorService (already had QR generation and TOTP verification)
- Added VerifyTOTPCode helper method to TwoFactorService
- All endpoints properly authenticated with RequireAuth middleware
Phase: PHASE-1
Priority: P0
Progress: 4/267 (1.5%)