manicanldes-backend/docs/identity-api.md

6.2 KiB
Raw Blame History

Phase 1B: identity and access API

All paths below start with /api/v1. Protected endpoints require Authorization: Bearer <accessToken>. There are no public account-creation or owner-creation endpoints. Staff account provisioning is available to authorized administrators; storefront self-registration and verified email onboarding can be added with the customer milestone.

Endpoints

Method Path Permission Request / result
POST /auth/login Public; throttled organizationId, email, password → accessToken, tokenType, expiresAt
GET /auth/me Authenticated userId, organizationId, sessionId, effective permissions
POST /auth/logout Authenticated Revoke current session; 204
POST /auth/logout-all Authenticated Revoke all current user sessions; 204
POST /auth/recovery/request Public; throttled organizationId, email → generic 202; 503 if SMTP is unconfigured
POST /auth/recovery/reset Public; throttled token, password → 204; token expires and can be consumed once
GET /users users.read Paginated safe user records
POST /users users.create name, email, password → PENDING account
PATCH /users/:id/status users.approve status: ACTIVE or SUSPENDED
PATCH /users/:id/roles users.roles.assign roleIds: UUID array; replaces assignments
GET /roles/permissions roles.read Current permission catalogue
GET /roles roles.read Paginated roles
POST /roles roles.manage name, permissions
PATCH /roles/:id roles.manage Complete replacement of name and permissions
GET /audit-events audit.read Paginated append-only organization audit history

List queries accept limit (1100, default 25) and offset (010000, default 0). Unknown fields, malformed UUIDs, duplicate role assignments/permissions and unknown permissions are rejected. Errors use Nest's JSON error contract: 400 invalid input, 401 unauthenticated, 403 denied, 404 missing/out-of-scope target, 409 duplicate record, 429 throttled, 503 unavailable.

Example login:

{
  "organizationId": "<UUID returned by bootstrap>",
  "email": "owner@example.com",
  "password": "<your passphrase>"
}

Access rules

Organization scope comes from the persisted session, never from an administration request body. Email uniqueness is per organization and normalized to lowercase. New accounts have no roles and cannot sign in until approved. Multiple roles combine their permissions. Permissions are reloaded on every request and rechecked inside administration transactions.

Administrators cannot grant permissions they do not hold, modify a more privileged role, change their own role assignments, assign the system Owner role, or change the owner's approval state. A single installation owner is created by the CLI; API-supplied owner flags are rejected. Suspending a user revokes sessions and recovery tokens; reactivation does not restore them.

An organization represents an access boundary, not a customer or supplier by default. No organization onboarding API, SaaS subscription isolation, MFA, SSO or social login is included in this milestone.

Passwords, sessions and recovery

Passwords require 15128 characters and use salted asynchronous scrypt (N=32768, r=8, p=3). Session and recovery secrets use 256 bits of randomness; only SHA-256 token digests are persisted. Sessions expire after the configured absolute lifetime. No refresh-token flow is needed for this opaque-session design; clients sign in again after expiry.

Recovery links put the token in the URL fragment; the future frontend must read it, submit it to the reset endpoint and remove it from browser history. Never log request bodies or authorization headers at the reverse proxy. Recovery resets invalidate all sessions and other recovery tokens in the same transaction. A failed SMTP send discards that token and logs a sanitized failure; users can request again after the throttle window.

Recovery delivery is synchronous in this milestone. The response body does not reveal account existence, but response timing is not constant. Durable queued delivery and retries belong to the notification milestone before a public storefront launch. No real emails are sent by the test suite.

Audit and abuse protection

Successful logins, known-account login failures, logout, password recovery/reset, user provisioning/approval/suspension and role changes are audited. Mutations and audit inserts share a transaction. Audit rows accept no arbitrary metadata and database triggers reject updates/deletes. Deploy with a restricted application database role; database owners can bypass database controls.

Auth routes share a database-backed IP limit of 30 requests/minute. Login also permits 10 attempts/account/15 minutes; recovery requests permit 3/account/15 minutes. Limits persist across instances. Proxy trust is disabled: behind a proxy, IP throttling groups requests under its address until an explicitly trusted proxy policy is configured. Use an edge rate limiter as well before public launch.

Expired sessions, recovery tokens and rate-limit rows can be removed by a controlled housekeeping job using their indexed expiry columns. Audit retention requires an explicit archival policy and privileged maintenance procedure; the API never deletes audits.

References: Node crypto, Nodemailer SMTP.