3.8 KiB
3.8 KiB
Business Rules — Unit 0: Backend Prerequisites
BR-U0-01: CORS Origin Validation
- The CORS policy MUST only allow origins listed in
Cors:AllowedOriginsfrom configuration - An empty
AllowedOriginsarray in production means no SPA origin is allowed (safe default) AllowCredentials()MUST be set — required for the browser to send the httpOnly cookieAllowAnyMethod()andAllowAnyHeader()are used to avoid CORS issues for future endpoints- The CORS middleware MUST be registered BEFORE
UseAuthenticationandUseAuthorizationin the pipeline
BR-U0-02: Refresh Token Cookie — Set Rules
- Cookie name:
refreshToken - Cookie path:
/api/v1/auth— scoped to auth endpoints only; not sent with other API calls HttpOnly = true— ALWAYS, no exceptionsSecure = request.IsHttps— adapts to the current request protocol (true in production, false in local HTTP)SameSite = Strict— cookie only sent when request originates from the exact same site- Cookie is set on BOTH
LoginandRefreshresponses (token rotation) - Cookie MUST NOT be set on failed auth attempts
BR-U0-03: Refresh Token Cookie — Clear Rules
- On
Revoke: Set-Cookie with the same name/path butExpires = DateTime.UnixEpoch(epoch = effectively deleted) - On failed refresh (invalid/expired token): Clear the cookie in the error response
- Cookie clearing MUST use the exact same
Pathas cookie setting (/api/v1/auth)
BR-U0-04: HTTP Response Body — Login and Refresh
The following fields MUST be returned in the response body:
accessToken(string) — JWT bearer tokenexpiresAt(ISO datetime) — access token expiryuser.id(Guid)user.email(string)user.name(string) —ApplicationUser.DisplayName ?? ApplicationUser.Emailuser.role(string) — the user's primary role name (Owner / Admin / User)user.isActive(bool)
The refreshToken MUST NOT appear in the response body.
BR-U0-05: Revoke Endpoint Authorization
[Authorize]is REMOVED from theRevokeendpoint- If the refresh token cookie is present: revoke it and clear the cookie
- If the refresh token cookie is absent: no-op, return
204 No Content(idempotent logout) - This allows logout to succeed even when the access token has already expired
BR-U0-06: Refresh Endpoint — Input
- The
RefreshTokenRequestbody parameter is REMOVED - The refresh token is read exclusively from
Request.Cookies["refreshToken"] - If the cookie is absent: return
401 Unauthorizedwith a generic error message - The existing
accessTokenvalidation logic inIAuthService.RefreshTokenAsynccan be relaxed or the signature adapted (see code generation for details)
BR-U0-07: DisplayName Field
ApplicationUser.DisplayNameis nullable (string?)- Maximum length: 100 characters
- Default value:
NULLfor existing users namein the response is computed as:user.DisplayName ?? user.Email- On new user creation via invitation (
POST /users/complete-setup): theDisplayNameis set from the form field - On owner creation (
POST /setup/owner):DisplayNamedefaults toNULL(falls back to email)
BR-U0-08: Migration
- A new EF Core Code-First migration is required named e.g.
AddDisplayNameToApplicationUser - The migration adds
DisplayName nvarchar(100) NULLto theAspNetUserstable - All existing users receive
NULLas theirDisplayName(they see their email as display name)
BR-U0-09: Security Baseline Compliance (SECURITY-12)
- httpOnly cookie prevents XSS token theft ✅
Secure = request.IsHttpsensures the cookie is only sent over HTTPS in production ✅SameSite=Strictprevents CSRF attacks on the refresh endpoint ✅- No credentials (tokens) in localStorage or response body ✅
- Session invalidated on logout (token revoked + cookie cleared) ✅