Skip to content

hard: role-gated endpoints trust stale JWT role claims — blocked/downgraded users keep permissions until token expiry #122

Description

@EmeditWeb

Problem

The JWT carries a role claim baked in at signing time (src/modules/auth/auth.service.ts, lines 160–168), and the comment admits the model: roles refresh only when the client calls POST /auth/refresh. PATCH /users/me/role (src/modules/users/users.controller.ts, lines 80–108) explicitly instructs clients to refresh afterward. This means:

  1. A user who sets themselves vendor (or any privileged role available in SetRoleDto) and later becomes malicious keeps that role in every outstanding access token until expiry — role revocation is advisory, not enforced.
  2. Combined with the blocked-status gap (separate issue), there is currently NO server-side authorization checkpoint between a valid signature and a role-gated action.
  3. The one-time role selection itself (setRole) has no recovery path: a misclick permanently binds sponsor|vendor|mentor, and admin tooling to reset it does not exist — support incidents become permanent.
  4. findOrCreateUser() auto-upserts ANY wallet presenting a valid token (line 144–158), meaning role assignment and profile creation happen implicitly outside any vetted flow.

Ground Rules

  1. Read context/architecture-context.md, context/code-standards.md, context/progress-tracker.md in full
  2. Read src/auth/guards/roles.guard.ts, jwt.strategy.ts, and the users module in full
  3. Coordinate with the admin-guard issue if both land — shared status-resolution helper preferred

What To Build

  1. Centralize authorization on server truth: guards resolve the user's CURRENT role/status from the datastore (short-TTL cached, consistent with the staleness bound chosen in the companion issues) and treat the JWT claim as a hint only.
  2. Add an admin-only role-management endpoint (or extend the admin module) allowing role reset/removal with full audit logging via the existing audit interceptor.
  3. Tighten setRole transition rules: define allowed transitions (e.g. none after first set, except admin reset) and enforce them in one place.
  4. Tests: downgraded user loses access within the documented bound; admin reset works end-to-end; audit events emitted; stale-token attacks rejected despite valid signature.

Files To Touch

  • src/auth/guards/roles.guard.ts
  • src/modules/users/users.controller.ts
  • src/modules/users/users.service.ts
  • src/modules/admin/ (new role-management surface)
  • tests
  • relevant docs/progress tracker

Acceptance Criteria

  • Role changes take effect server-side within a bounded, documented delay regardless of token age
  • Admin reset path exists and is audited
  • Suite green

Mandatory Checks Before Opening PR

Standard checklist applies. PRs failing any check will be closed without review.

Metadata

Metadata

Labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions