colidevs / colidevs/create-coliapp
nextjs-shadcn-ecommerce-admin: admin console has no MFA/passkey, single hardcoded role
- Dominant language
- TypeScript
- Stars
- 2
- Forks
- 0
- Avg merge
- 4h 42m
- Merged PRs (30d)
- 43
Description
## Context
Found via a full `api-standard-check`/`frontend-standard-check` audit (ADR 0009-0013, ADR 0019-0024) of
the new `templates/nextjs-shadcn-ecommerce-admin` template, run against the final branch of the
`ecommerce-admin-template` SDD build (PR stack #43-#53, all still open/unmerged at filing time). This
does **not** block that PR stack's review — it's tracked here as follow-up hardening, matching this
repo's existing "detection now, fix later" convention.
## Finding
`apps/api/src/lib/ability.ts`'s `resolveRole()` (lines 82-84) grants **every authenticated session** the
full `"admin"` CASL role — there is no per-user role column, and no viewer/lower-privilege tier is
actually reachable in practice. Auth is `emailAndPassword` only (`src/lib/auth.ts:119-132`); no
passkey/WebAuthn or TOTP plugin is registered anywhere. The same finding shows up independently on the
frontend side (`apps/web/src/lib/ability.ts`'s mirrored `resolveRole`).
This means the entire admin console — catalog CRUD, stock, and order/buyer-PII visibility — sits behind
single-factor password auth with no real authorization tiering. Per ADR 0010
(`api-security-baseline.md`), MFA (or an AAL2-satisfying passkey) is **mandatory for admin/owner roles**,
and per ADR 0013, Passkeys/WebAuthn are already adopted-now for admin-console human sign-in.
A code comment citing `colidevs/munod#44` as precedent exists, but it's not recorded as a formal
`exception` (no `reason`/`approver`/`review_after`), so this stays an open finding rather than an
accepted, time-boxed deviation.
## Related, lower-severity finding bundled here
`apps/api/src/api.ts:71-78`: a single global rate limiter (300 req/15 min) applies uniformly to
`/api/auth/*` and every other route — no auth-endpoint-specific throttle, no CAPTCHA/Turnstile. ADR 0013
calls for tighter, endpoint-specific limits on login/auth flows given their disproportionate abuse value.
## Why this matters for a real client
This template is meant to be scaffolded directly for real client projects (e.g. the Ecuador
storefront+admin project that motivated building it). Shipping it as-is means every real deployment
starts with no real per-user roles and no MFA on the admin console — worth closing before the first real
client goes live, not necessarily before this PR stack merges.
## Suggested fix shape
- Add a real per-user role column/table (mirrors ADR 0013's `user_tenant_roles`-shaped design, minus the
tenant dimension per this template's own single-tenant deviation) and wire `resolveRole()` against it.
- Add Better Auth's `passkey` plugin (already an adopted, named pattern per ADR 0013/0014) for admin
sign-in.
- Add an endpoint-specific rate limit + Turnstile on `/api/auth/*`.
Not fixed in this issue — filing for tracking per the audit's own recommendation.
Contributor guide
No contributing guide indexed for this repository
Research direction
Start with ADRs 0010, 0013, and 0014, then inspect apps/api/src/lib/ability.ts, apps/web/src/lib/ability.ts, apps/api/src/lib/auth.ts, and apps/api/src/api.ts. Trace resolveRole(), authentication setup, and the global limiter before deciding how the proposed role, passkey, and auth-endpoint protections fit together. Done means real role-based access, admin MFA or passkey sign-in, and tighter auth throttling with Turnstile.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- next.js, typescript
- Domain
- api, authentication, authorization, backend, frontend, security
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100