Files
slp-modular-cms/aidlc-docs/features/cms-frontend/construction/unit-0/functional-design/business-rules.md
T

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:AllowedOrigins from configuration
  • An empty AllowedOrigins array in production means no SPA origin is allowed (safe default)
  • AllowCredentials() MUST be set — required for the browser to send the httpOnly cookie
  • AllowAnyMethod() and AllowAnyHeader() are used to avoid CORS issues for future endpoints
  • The CORS middleware MUST be registered BEFORE UseAuthentication and UseAuthorization in the pipeline
  • Cookie name: refreshToken
  • Cookie path: /api/v1/auth — scoped to auth endpoints only; not sent with other API calls
  • HttpOnly = true — ALWAYS, no exceptions
  • Secure = 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 Login and Refresh responses (token rotation)
  • Cookie MUST NOT be set on failed auth attempts
  • On Revoke: Set-Cookie with the same name/path but Expires = 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 Path as 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 token
  • expiresAt (ISO datetime) — access token expiry
  • user.id (Guid)
  • user.email (string)
  • user.name (string) — ApplicationUser.DisplayName ?? ApplicationUser.Email
  • user.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 the Revoke endpoint
  • 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 RefreshTokenRequest body parameter is REMOVED
  • The refresh token is read exclusively from Request.Cookies["refreshToken"]
  • If the cookie is absent: return 401 Unauthorized with a generic error message
  • The existing accessToken validation logic in IAuthService.RefreshTokenAsync can be relaxed or the signature adapted (see code generation for details)

BR-U0-07: DisplayName Field

  • ApplicationUser.DisplayName is nullable (string?)
  • Maximum length: 100 characters
  • Default value: NULL for existing users
  • name in the response is computed as: user.DisplayName ?? user.Email
  • On new user creation via invitation (POST /users/complete-setup): the DisplayName is set from the form field
  • On owner creation (POST /setup/owner): DisplayName defaults to NULL (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) NULL to the AspNetUsers table
  • All existing users receive NULL as their DisplayName (they see their email as display name)

BR-U0-09: Security Baseline Compliance (SECURITY-12)

  • httpOnly cookie prevents XSS token theft
  • Secure = request.IsHttps ensures the cookie is only sent over HTTPS in production
  • SameSite=Strict prevents CSRF attacks on the refresh endpoint
  • No credentials (tokens) in localStorage or response body
  • Session invalidated on logout (token revoked + cookie cleared)