Phase 6 hardening: authentication, multi-user, and CSRF protection #25

Open
opened 2026-09-11 23:33:27 +00:00 by agent-pi · 1 comment
Collaborator

Problem

Every reader route acts as a hard-coded user_id = 1 (annotated # Phase 6 will add multi-user), there is no authentication or session layer, and all state-changing POST routes (article read/unread, aggregate mark-read, feed add/delete, tag management) accept requests without any CSRF protection. Any client that can reach the server can mutate data on behalf of the default user. WuMing raises this on every PR that touches a state-changing route (latest: PR #24), and each occurrence is declined as project-level work — this issue is where that work belongs.

Goal

  • Authentication with per-user sessions; routes derive the acting user from the session instead of hard-coding an ID
  • Authorization checks so users act only on their own data
  • CSRF protection on all state-changing routes
  • Completes the planned Phase 6 multi-user support
## Problem Every reader route acts as a hard-coded `user_id = 1` (annotated `# Phase 6 will add multi-user`), there is no authentication or session layer, and all state-changing POST routes (article read/unread, aggregate mark-read, feed add/delete, tag management) accept requests without any CSRF protection. Any client that can reach the server can mutate data on behalf of the default user. WuMing raises this on every PR that touches a state-changing route (latest: PR #24), and each occurrence is declined as project-level work — this issue is where that work belongs. ## Goal - Authentication with per-user sessions; routes derive the acting user from the session instead of hard-coding an ID - Authorization checks so users act only on their own data - CSRF protection on all state-changing routes - Completes the planned Phase 6 multi-user support
Author
Collaborator

Findings

  • The data layer is already multi-user-ready: users table + User model + db/users.py accessors exist, and read_status is keyed by (user_id, article_id). The gap is routes/sessions, not schema.
  • Origin: WuMing A01 findings on PR #24 (hard-coded user_id = 1; missing CSRF) — declined there as project-level, to be tracked here.
  • CSRF has no browser-forgery exposure while no cookies/sessions exist; it becomes real the moment sessions land, so it belongs in the same effort.
  • Library choices (auth/session approach, CSRF mechanism, e.g. Flask-WTF) are undecided — to be selected against evidence during design, per house rules.

Plan of attack

  1. Design pass: auth/session approach + CSRF mechanism, commented here before implementation.
  2. Login/logout + session-derived user; replace every hard-coded user_id = 1.
  3. Authorization checks on per-user resources.
  4. CSRF protection across all state-changing routes; update forms and tests.
  5. Multi-user UI as needed for Phase 6.
## Findings - The data layer is already multi-user-ready: `users` table + `User` model + `db/users.py` accessors exist, and `read_status` is keyed by `(user_id, article_id)`. The gap is routes/sessions, not schema. - Origin: WuMing A01 findings on PR #24 (hard-coded `user_id = 1`; missing CSRF) — declined there as project-level, to be tracked here. - CSRF has no browser-forgery exposure while no cookies/sessions exist; it becomes real the moment sessions land, so it belongs in the same effort. - Library choices (auth/session approach, CSRF mechanism, e.g. Flask-WTF) are undecided — to be selected against evidence during design, per house rules. ## Plan of attack 1. Design pass: auth/session approach + CSRF mechanism, commented here before implementation. 2. Login/logout + session-derived user; replace every hard-coded `user_id = 1`. 3. Authorization checks on per-user resources. 4. CSRF protection across all state-changing routes; update forms and tests. 5. Multi-user UI as needed for Phase 6.
Sign in to join this conversation.
No labels
No milestone
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Reference
marvin8/yunjin#25
No description provided.