Skip to content

auth: PIN login gate - one-time login issues in-memory session tokens - #4

Merged
SamAnaniasCases merged 1 commit into
mainfrom
auth-security
Sep 11, 2026
Merged

SamAnaniasCases merged 1 commit into
mainfrom
auth-security

Conversation

@SamAnaniasCases

@SamAnaniasCases SamAnaniasCases commented Sep 4, 2026

Copy link
Copy Markdown
Contributor

Description

  • app/services/sessions.py: module-level token set (secrets.token_urlsafe), no persistence - a restart invalidates every token, and since config loads once at startup a PIN change is a restart, so one rule covers both re-prompt triggers
  • require_pin additively accepts a valid token in X-Session-Token; the raw X-API-PIN header path is unchanged
  • new GET /auth/status (always 200; pin_required + session_valid true/false/null) and POST /auth/login (401 wrong PIN, 400 when no PIN is configured); router mounted in app/main.py
  • web: shared gate overlay (GATE_HTML) on both pages styled as a third notebook page, Remember checkbox picks localStorage vs sessionStorage, the old per-action id="pin" field and its JS read sites are gone in favor of one authHeaders() helper, 401 mid-action re-raises the gate, and checkGate() rides the 30 s health poll for restart re-prompt
  • docs: LOGIN_PLAN.md decision record (review + as-built), WEBDESIGN_PLAN §12 addendum, SOURCE_OF_TRUTH §8/§11, README/.env.example API_PIN text

Type of change

  • Bug fix
  • New feature
  • Refactor / cleanup
  • Documentation
  • Other (describe below)

Related issue

How was this tested?

  • tests: new unit (sessions, token path of require_pin), API (/auth/status, /auth/login, token-unlocks-route integration) and web gate tests plus an autouse fresh_sessions fixture; suite 316 -> 378, coverage 95.75 %, ruff clean

Screenshots (if applicable)

Checklist

  • My code builds and runs locally
  • I've tested the change
  • I've updated docs/comments where needed

- app/services/sessions.py: module-level token set (secrets.token_urlsafe),
  no persistence - a restart invalidates every token, and since config
  loads once at startup a PIN change is a restart, so one rule covers both
  re-prompt triggers
- require_pin additively accepts a valid token in X-Session-Token; the
  raw X-API-PIN header path is unchanged
- new GET /auth/status (always 200; pin_required + session_valid
  true/false/null) and POST /auth/login (401 wrong PIN, 400 when no PIN
  is configured); router mounted in app/main.py
- web: shared gate overlay (GATE_HTML) on both pages styled as a third
  notebook page, Remember checkbox picks localStorage vs sessionStorage,
  the old per-action id="pin" field and its JS read sites are gone in
  favor of one authHeaders() helper, 401 mid-action re-raises the gate,
  and checkGate() rides the 30 s health poll for restart re-prompt
- docs: LOGIN_PLAN.md decision record (review + as-built), WEBDESIGN_PLAN
  §12 addendum, SOURCE_OF_TRUTH §8/§11, README/.env.example API_PIN text
- tests: new unit (sessions, token path of require_pin), API
  (/auth/status, /auth/login, token-unlocks-route integration) and web
  gate tests plus an autouse fresh_sessions fixture; suite 316 -> 378,
  coverage 95.75 %, ruff clean
@SamAnaniasCases
SamAnaniasCases merged commit 5bf018f into main Sep 11, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant