SUBTASK #86: Sessions and route protection in the Application Controller (2.0)

Open
#90 0 comments 0 reactions 1 assignee View on GitHub

Maintainers usually reply within 1 day

@javi120467 is already working on this.

Since Nov 2, 2026.

Assessment

Difficulty
4/5
Estimated time
3-5 days
Newbie friendliness
22/100
Issue type
Feature
Clarity
Mostly clear
Activity status
Active
Tech stack
flask, python

Research direction

Start from the Application Controller package from #50, then add the auth module at backend/controller/auth.py with its tests in tests/controller/test_auth.py. The SECRET_KEY note goes in the .env section of README.md. Build the @requires and @public decorators and the /api/login, /api/logout and /api/me routes, and run the Flask test client tests without a database. Done when those tests pass and an unauthenticated GET /api/devices returns 401. The issue depends on #88, #89 and #50, which are not yet complete.

Written by the indexing model from the issue text.

Description

backend Low Priority security subtask

What to do

Connect access control to the Flask app from #50: sign-in, sign-out and "who am I" endpoints, a secure session cookie, and a permission check on every API route, so a request that isn't allowed never reaches a service.

Background

  • Spec SEC-01, SEC-03, SEC-07, SEC-09, CP-01, CM-11; AT-13 (an action the role doesn't permit is rejected and logged)
  • System design 11.2: session cookie Secure, HttpOnly, SameSite=Strict; ApplicationController.checkPermissions() → AccessControlService.authorizeAction()
  • System design 12: Flask's built-in session handling
  • Permissions are subtask 2; sign-in is subtask 3. Session length is a decision on #PARENT.

Steps

  • Settings:
    • SECRET_KEY from .env. The app refuses to start if it's missing or shorter than 32 characters. The README shows how to make one: py -3.13 -c "import secrets; print(secrets.token_hex(32))"
    • Cookie: HttpOnly, SameSite=Strict, and Secure whenever the app is served over HTTPS (HTTPS itself arrives in M7)
    • Signed out after 8 hours in any case, and after 30 minutes without a request (a "last seen" time in the session, checked on each request)
  • Endpoints:
    • POST /api/login with {username, password}: 200 with the user (to_dict()) and their permissions, or 401 with {"error": reason}. On success, clear the session before storing the user id, so a session made before sign-in can't be reused (session fixation).
    • POST /api/logout: clears the session, 204
    • GET /api/me: the signed-in user and their permissions, or 401
  • Route protection:
    • @requires(Permission.X) on every route: loads the user from the session on each request; 401 if not signed in, timed out or disabled (and clears the session); 403 with the reason from authorize if the role isn't allowed; otherwise puts the user on flask.g.user
    • @public only on POST /api/login
    • A test that walks app.url_map and fails if any /api/ route has neither
  • Refused requests are logged at WARNING: user, permission and path, never the request body
  • Starting a scan (#51) takes the user from g.user, not from the request body (CM-11)
  • Requests that change data must be JSON (Content-Type: application/json), otherwise 415. Together with SameSite=Strict, this stops another website from submitting changes using a signed-in user's cookie (CSRF).
  • Unit tests (Flask test client, fake stores, a fake clock):
    • Signed out: every /api/ route except login gives 401
    • A viewer gets 403 on starting a scan, and 200 on the device list
    • The login response sets a cookie marked HttpOnly and SameSite=Strict
    • After sign-out, the old cookie gives 401
    • A user disabled after signing in gets 401 on their next request
    • 31 minutes without a request gives 401
    • No response body contains password_hash or $argon2
    • A refused request is logged without the password (assertLogs)
    • A form-encoded POST gives 415

Where

  • The Application Controller package from #50 (e.g. backend/controller/auth.py)
  • tests/controller/test_auth.py
  • README.md (the SECRET_KEY line in the .env section)

Done when

  • All the tests above pass without a database
  • With the app running, GET /api/devices signed out gives 401, and after signing in as a viewer gives the list

Depends on

  • Roles and permissions (#88) and Sign in (#89)
  • Application entry point and Application Controller (#50)
  • Scan and device API endpoints (#51)
Dominant language
Python
Stars
1
Forks
1
Avg merge
9h 31m
Merged PRs (30d)
36

Getting set up

This project ships no dev container, Dockerfile or contributing guide, so setting up is up to you: start from its README, and see our first-contribution guide for the general steps.

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

More from Bearkat-Professionals/Software-Engineering-Project

All issues in Bearkat-Professionals/Software-Engineering-Project

Similar issues

More Python issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.