The authentication foundation uses ASP.NET Core Identity with the application database as the Identity store.
Two first-party client modes are supported:
HttpOnly.residential-auth with SameAsRequest secure policy.__Host-residential-auth with Secure=Always, Path=/ and no Domain.SameSite=Lax.There is intentionally no public registration endpoint.
A resident must not be able to create an account and assign themselves to an arbitrary unit. DEC-014/RB-024 decides that resident onboarding is Administrator-created with email verification and resident-set password.
Identity currently enforces:
Password hashes are produced and managed by ASP.NET Core Identity. Plaintext passwords are never persisted by application code.
Initial roles:
ResidentAdministratorPolicies:
ResidentAccess: Resident or Administrator.Administrator: Administrator only.The backend derives roles from the Identity store/claims principal. Role names supplied in client request bodies are never authoritative.
Building/unit authorization remains a separate domain concern through active ResidentMembership records. Authentication answers who the user is; membership answers which building/unit context the user may operate in.
Current controlled endpoints:
POST /api/auth/loginPOST /api/auth/refreshPOST /api/auth/logoutGET /api/auth/meGET /api/auth/check/resident — verification endpointGET /api/auth/check/admin — verification endpointThe check endpoints exist to prove policy enforcement during the foundation phase and can be removed/replaced as real protected use cases appear.
Implemented in issue #24:
POST /api/webhooks/mercadopago is anonymous by necessity but every call
must carry a valid x-signature (HMAC-SHA256 over
id:<data.id>;request-id:<x-request-id>;ts:<ts>;, constant-time compare,
timestamp tolerance). Invalid → 401, nothing stored, nothing fetched.data.id query; the order is then re-fetched with the private token
and its id, external_reference, amount and currency are validated against
the local payment.X-Idempotency-Key, unique provider order/event ids,
state-based reconciliation.x-signature,
Authorization, payer data.Developer-specific API secrets use .NET User Secrets or environment variables and never live in source-controlled configuration. Development CORS remains an explicit allowlist.
See Local Development Security for secret names, logging rules and the future Mercado Pago/Azure checklist.
Still to be addressed/refined in later issues:
Cash (issue #25): declaring cash is limited to the reservation’s creator (or
an Administrator); confirming receipt is Administrator-only by DEC-015/RB-026,
with the actor always taken from the authenticated session and stored on the
payment (CashConfirmedByUserId, CashConfirmedAtUtc). The resident-facing
payment view never exposes that id.
AuditLog; corrections are new events. It is read through
GET /api/admin/audit, restricted to Administrator.Authorization headers; secrets (Mercado Pago access token, webhook
secret); x-signature; connection strings; card data; checkout URLs;
idempotency keys; full request/response bodies; payer personal data; and the
e-mail typed at a failed login.AuditMetadata); nothing accepts an arbitrary dictionary or client input,
and there is no middleware that stores requests.InvalidCredentials), no user id and no submitted identifier; the HTTP
response is unchanged, so audit does not enable user enumeration./api/admin/... route is under the Administrator policy (anonymous
401, Resident 403); the actor is always the authenticated session user, and a
client-sent role or actor id is ignored.AuditLogs, see the audit section).