planner-auth / README.md
Offlin33er's picture
README translated to English
907c7ec verified
|
Raw History Blame Contribute Delete
3.33 kB
metadata
title: Planner Auth — Real Authentication
emoji: 🔐
colorFrom: indigo
colorTo: green
sdk: docker
app_port: 7860
pinned: false
license: mit

Planner Auth 🔐

A real (server-side) authentication server + protected planner: passwords hashed with bcrypt, sessions managed by the server with an httpOnly cookie, each user's data stored and filtered on the server, and an /app page that only opens with a valid session.

How to use it

  1. Open the Space → Sign up → create an account → click Open the Planner.
  2. The planner (/app) loads habits, tasks and focus sessions from the server API — nothing in IndexedDB.
  3. Try opening /app while logged out: the server redirects you to the login.
  4. Reload the page: you're still logged in (the session lives on the server).

Endpoints

Authentication

Route What it does
POST /api/register validates, hashes with bcrypt (10 rounds), creates the user, starts a session
POST /api/login bcrypt compare, regenerates the session (anti fixation), rate limit of 5 tries / 15 min
POST /api/logout destroys the session on the server
GET /api/me protected — returns the session's user, or 401
POST /api/forgot-password random token, stored only as a SHA-256 hash, 15 min validity
POST /api/reset-password validates the token (single use) and replaces the password hash

Per-user data — all require a session and filter by owner

Route What it does
GET/POST /api/habits, PUT/DELETE /api/habits/:id the logged-in user's habits (emoji, color, daily/weekly with a goal)
GET /api/checkins, POST /api/checkins/toggle daily completions ({habitId, date}), validates habit ownership
GET/POST /api/tasks, PUT/DELETE /api/tasks/:id, POST /api/tasks/reorder tasks with priority and due date, reordering by id list
GET/POST /api/sessions focus (pomodoro) sessions
GET /app the planner page — redirects to / without a session

Security details

  • bcrypt with 10 rounds — the password is never stored as plain text.
  • Server-side session: the planner.sid cookie is httpOnly, sameSite=lax, automatically Secure behind the Space's HTTPS; secret generated with crypto.randomBytes and persisted.
  • Session regeneration on login (anti fixation) and login rate limiting.
  • /app outside express.static: the file lives in private/ and is only served by the route that requires a session — there is no way to download it directly.
  • Per-user isolation on the server: every data route filters by owner = current session; a user cannot read or change another user's data, even by forging ids.
  • Reset token stored as a SHA-256 hash, single use, expiring; the "forgot password" response is identical whether the e-mail exists or not.

Honest limitations

  • Storage is data/db.json (swap for SQLite/Postgres in production).
  • Sessions are in memory (MemoryStore) — they don't survive a Space restart; use Redis in production.
  • No e-mail in a Space: the reset token comes back in the API response (demo). In production it would go by e-mail.
  • No explicit CSRF token (sameSite=lax covers the basic case); no HTTPS of its own (the Space proxy handles it).