Skip to content

Conversation

@ebigunso
Copy link
Owner

Summary

This PR implements PR-A: single-user session authentication, double-submit CSRF protection, and security headers for the Axum backend. It protects the /trends UI route and all mutating API routes, while keeping non‑mutating GET routes open.

Key changes

  • Auth
    • Added /login (GET/POST) and /logout endpoints
    • Encrypted + signed session cookie __Host-session (Secure, HttpOnly, SameSite=Lax, Path=/) via axum-extra PrivateCookieJar
    • AppState introduced with Db + Key; FromRef implemented for Db and Key
    • RequireSessionJson (401 JSON on unauthenticated) and RequireSessionRedirect (302 to /login for UI)
  • CSRF (double-submit)
    • Issued __Host-csrf cookie (Secure, SameSite=Lax, Path=/; not HttpOnly), URL‑safe base64 token
    • CsrfGuard verifies header X-CSRF-Token equals the cookie value (percent-decoding supported) for POST/PUT/DELETE
    • Same-site heuristic using Sec-Fetch-Site if present
  • Security headers
    • X-Content-Type-Options: nosniff
    • X-Frame-Options: DENY
    • Referrer-Policy: strict-origin-when-cross-origin
    • Content-Security-Policy: default-src 'self'; script-src 'self' 'unsafe-inline'
    • Strict-Transport-Security when ENABLE_HSTS=1/true
  • Route protection
    • /trends protected via RequireSessionRedirect
    • Mutating routes protected via RequireSessionJson + CsrfGuard:
      • POST /sleep, PUT /sleep/{id}, DELETE /sleep/{id}
      • POST /exercise, POST /note
    • Open routes remain: GET /health, GET /sleep/date/{date}, GET /api/trends/*
  • Config and tooling
    • .env.example with ADMIN_EMAIL, ADMIN_PASSWORD_HASH, SESSION_SECRET, CSRF_SECRET placeholder, ENABLE_HSTS
    • session_key() derives Key from SESSION_SECRET or generates fallback
    • hsts_enabled() reads ENABLE_HSTS
    • pw-hash helper (cargo run -p sleep-api --bin pw-hash) to generate Argon2id hashes
  • Documentation
    • Added module and item docs for auth, CSRF, headers, middleware extractors, AppState, config helpers, and pw-hash, with examples and references

Tests

  • New: tests/auth_csrf.rs validates:
    • Unauth /trends redirects to /login
    • Login emits __Host-session and __Host-csrf
    • Mutating without CSRF → 403; with matching header + cookie → success
    • Logout → subsequent mutating returns 401
  • Updated: tests/api_sleep.rs and tests/trends_bars.rs
    • Added login step, send Cookie (__Host‑session, __Host‑csrf) + X‑CSRF‑Token for mutating calls
    • Bound to 127.0.0.2 for isolation

Quality gates

  • cargo clippy -- -D warnings passes
  • cargo test -p sleep-api passes (unit, integration, doc tests)

Security & operational notes

  • __Host- cookies require Secure and Path=/; browsers won’t persist over plain HTTP. Automated tests are unaffected. For local browser dev, use TLS (reverse proxy/local certs) or feature-gate for HTTP if necessary.
  • Session is cookie-only; optional session expiry/idle timeouts can be added later.

Follow-ups (optional)

  • Add session expiry/idle timeouts and login rate limiting
  • Tighten CSP in a future PR (remove 'unsafe-inline', add nonces)
  • Expand frontend UI for login

…login and /logout; protect /trends and mutating APIs; add tests (auth_csrf) and update existing tests; switch CSRF token to URL-safe base64; clippy clean
…ppState, config, and pw-hash; align with existing project style
Copilot AI review requested due to automatic review settings August 11, 2025 17:53

This comment was marked as outdated.

…y warnings in tests (format args, remove needless borrows); keep unsafe env var blocks per project guidance. Refs #5
@ebigunso ebigunso requested a review from Copilot August 11, 2025 18:36

This comment was marked as outdated.

…itch RNG sources to password-hash rand_core OsRng to resolve rand_core version mismatch; run cargo fmt and clippy; address PR feedback. Refs #5
@ebigunso ebigunso requested a review from Copilot August 11, 2025 19:05
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR implements comprehensive security features for the Axum backend including single-user session authentication, double-submit CSRF protection, and security headers. It protects the /trends UI route and all mutating API routes while keeping GET routes open for public access.

Key changes:

  • Added session-based authentication with encrypted cookies and login/logout endpoints
  • Implemented double-submit CSRF protection for all mutating requests (POST/PUT/DELETE)
  • Added security headers including CSP, X-Frame-Options, and optional HSTS

Reviewed Changes

Copilot reviewed 16 out of 18 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
sleep-api/tests/trends_bars.rs Updated test to include authentication flow and CSRF token handling
sleep-api/tests/auth_csrf.rs New comprehensive test validating authentication and CSRF protection
sleep-api/tests/api_sleep.rs Updated existing API tests to authenticate and send CSRF tokens
sleep-api/src/trends.rs Minor string formatting improvement using string interpolation
sleep-api/src/security/mod.rs New module documentation for security utilities
sleep-api/src/security/headers.rs Implementation of security headers middleware
sleep-api/src/security/csrf.rs CSRF protection implementation with double-submit cookie pattern
sleep-api/src/middleware/mod.rs New middleware module documentation
sleep-api/src/middleware/auth_layer.rs Authentication extractors for session validation
sleep-api/src/main.rs Added new module declarations
sleep-api/src/lib.rs Exposed new modules in public API
sleep-api/src/config.rs Added configuration helpers for auth credentials and secrets
sleep-api/src/auth.rs Core authentication utilities for session management
sleep-api/src/app.rs Updated router with authentication routes and middleware
sleep-api/Cargo.toml Added required dependencies for authentication and CSRF
.env.example Configuration template with security settings

…use config-based names for session/CSRF cookies; switch to axum_extra::either::Either for /login form+JSON
… CSRF; update README for COOKIE_SECURE and double-submit
…t(session): add SESSION_TTL_HOURS Max-Age; feat(security): COOKIE_SECURE dev-mode cookie names/flags; refactor(csrf): dynamic cookie names and header handling; docs(openapi,README): add /login.json, securitySchemes and CSRF requirements; chore(CSP): add connect-src 'self'
…-protect /logout; gate GET /sleep/date and trends APIs by session. headers: CSP allow cdn.jsdelivr.net for Chart.js.
… protected endpoints; gate GET endpoints in spec. tests: CSRF required on logout; add percent-encoded CSRF header test and dev cookie flags test.
…tests; add percent-encoded token and dev cookie flags coverage. build: add serial_test dev-dep.
@ebigunso ebigunso self-assigned this Aug 11, 2025
@ebigunso ebigunso changed the title PR-A: Backend Auth, CSRF, and Security Headers ✨ Backend Auth, CSRF, and Security Headers Aug 11, 2025
@ebigunso ebigunso merged commit 62c9357 into main Aug 11, 2025
2 checks passed
@ebigunso ebigunso deleted the feature/2025-08-11/security-update branch August 11, 2025 22:04
@ebigunso ebigunso restored the feature/2025-08-11/security-update branch August 11, 2025 22:05
ebigunso added a commit that referenced this pull request Aug 11, 2025
ebigunso added a commit that referenced this pull request Aug 11, 2025
…y warnings in tests (format args, remove needless borrows); keep unsafe env var blocks per project guidance. Refs #5
ebigunso added a commit that referenced this pull request Aug 11, 2025
…itch RNG sources to password-hash rand_core OsRng to resolve rand_core version mismatch; run cargo fmt and clippy; address PR feedback. Refs #5
ebigunso added a commit that referenced this pull request Aug 11, 2025
ebigunso added a commit that referenced this pull request Aug 11, 2025
* PR-A: deps, .env.example, and pw-hash helper; add config for admin and session key

* PR-A: add auth, CSRF, and security header modules (scaffold)

* PR-A: wire AppState + session auth, CSRF, and security headers; add /login and /logout; protect /trends and mutating APIs; add tests (auth_csrf) and update existing tests; switch CSRF token to URL-safe base64; clippy clean

* 🎨 Format

* docs: add module and item docs for auth, CSRF, headers, middleware, AppState, config, and pw-hash; align with existing project style

* fix(doctest): make axum Router state explicit in doctest examples to satisfy type inference; all tests pass

* chore: replace eprintln! with tracing::debug in CSRF guard; fix clippy warnings in tests (format args, remove needless borrows); keep unsafe env var blocks per project guidance. Refs #5

* 🎨 Format

* chore(csrf): use percent-encoding crate for header token decoding; switch RNG sources to password-hash rand_core OsRng to resolve rand_core version mismatch; run cargo fmt and clippy; address PR feedback. Refs #5

* ⬆️ Update lock file

* 🎨 Format

* chore(csrf): move X_CSRF_TOKEN to module scope; remove unused rand dependency; run fmt/clippy. Refs #5

* Lock file update

* 🚨 Fix linter error

* fix(login): accept HTML form and JSON payloads for /login

* docs(csrf): remove unused CSRF_SECRET; clarify double-submit design

* feat(cookie): support dev-mode cookie names/flags via COOKIE_SECURE; use config-based names for session/CSRF cookies; switch to axum_extra::either::Either for /login form+JSON

* docs(openapi): add /login and /logout; document cookie-based auth and CSRF; update README for COOKIE_SECURE and double-submit

* feat(auth): split /login handlers (form + JSON) and update tests; feat(session): add SESSION_TTL_HOURS Max-Age; feat(security): COOKIE_SECURE dev-mode cookie names/flags; refactor(csrf): dynamic cookie names and header handling; docs(openapi,README): add /login.json, securitySchemes and CSRF requirements; chore(CSP): add connect-src 'self'

* auth: /login accepts form or JSON; form redirects 303. security: CSRF-protect /logout; gate GET /sleep/date and trends APIs by session. headers: CSP allow cdn.jsdelivr.net for Chart.js.

* spec: /login 303 form redirect; deprecate /login.json; add 401/403 to protected endpoints; gate GET endpoints in spec. tests: CSRF required on logout; add percent-encoded CSRF header test and dev cookie flags test.

* tests: isolate env with serial_test; enforce COOKIE_SECURE=1 in CSRF tests; add percent-encoded token and dev cookie flags coverage. build: add serial_test dev-dep.

* 🩹 Small fixes

* docs(app): add rustdoc for handlers and pages (auth, CRUD, trends) in app.rs
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.

2 participants