planner-auth / README.md
Offlin33er's picture
README translated to English
907c7ec verified
|
Raw History Blame Contribute Delete
3.33 kB
---
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).