Nobody has started this yet — be first.
Business impact
Currently POST /auth/login silently ignores any remember_me field in the request body -- every session gets a refresh token good for REFRESH_TOKEN_TTL_DAYS (30 days by default), no matter what the client asks for. REMEMBER_ME_REFRESH_TOKEN_TTL_DAYS (180 days by default) already exists in config but nothing reads it, so there is no way for a client to ask for a longer-lived session on a trusted device.
Problem
login() never reads remember_me from the request body, so every login gets the plain REFRESH_TOKEN_TTL_DAYS regardless of what the client asks for.
Current behavior
A login with remember_me: true still issues a refresh token whose lifetime matches REFRESH_TOKEN_TTL_DAYS, not REMEMBER_ME_REFRESH_TOKEN_TTL_DAYS.
Expected behavior
POST /auth/login with {"remember_me": true} issues a refresh token whose lifetime is REMEMBER_ME_REFRESH_TOKEN_TTL_DAYS instead of the normal REFRESH_TOKEN_TTL_DAYS. Everything else about the session (rotation, reuse detection, denylisting on logout/revoke) behaves identically regardless of which TTL was used to create it.
Steps to reproduce
Why this matters
This is a small end-to-end plumbing exercise: a value has to travel from the request body, through the route handler, through issue_token_pair(), into issue_refresh_token(), and finally into the expires_at written to the database -- with no existing parameter to carry it. It is a good exercise in extending an existing call chain without breaking any of its other callers (rotate_refresh_token() and the 2FA-verify login path both call into the same functions and must keep working exactly as before).
Suggested approach
Look at every call site of issue_token_pair() and issue_refresh_token() in tokens.py and routes.py. Decide how a "use this TTL instead of the config default" override should be threaded through without forcing every other caller to specify it -- login() is the only caller that should ever pass a non-default TTL.
Acceptance criteria
Verification
pytest practice_tickets/tests/test_ticket_08.py -v
Hints (0/2)
Try it without hints first — the reading is the exercise.
Working on this ticket
Work on a branch named for the ticket — that's what you'll submit.
Branch off your fork
Sign in to create it automatically, or do it yourself:
$git checkout -b feat/remember-meFix it and commit
Meet every acceptance criterion, and add a test that would have caught this.
Push the branch
$git push -u origin feat/remember-meSubmit it below
Paste your fork URL and the branch name, with a short write-up of the root cause.
Questions
Ask about anything unclear in the ticket — the maintainer and anyone who has solved it can answer. Please don't post full solutions.
Sign in to ask a question or reply.
Sign inhttp://localhost:5000make seedpyotpmake docker-prod-upYou do not need Docker running at all to work the tickets -- the test suite uses an in-memory SQLite database (via StaticPool, an isolated DB per test function) and fakeredis (TestingConfig.USE_FAKE_REDIS), so everything runs against a plain virtualenv:
python -m venv .venv && source .venv/bin/activate
pip install -r requirements.txt
pytest practice_tickets/tests/test_ticket_01.py -v # a single ticket
./practice_tickets/run_tickets.sh # all 15, clean pass/fail summary
All 15 tests fail at the start; as you fix each ticket in app/, its test (and only its test) should flip to passing. make test (pytest -q) runs the project's own main suite -- as of writing it shows 9 pre-existing failures caused by ticket bugs 02, 03, 07, 11, and 15; fixing those tickets fixes those failures too, not a separate task. Do not look at git diff / version control history to find the bugs if this repo is ever put under source control -- the point is to find them the way you would find a real bug: from a failing test and a description of broken behavior, not a diff.
Level 2
Implement a feature
Extend the system within its own patterns.