Credential Hygiene & Session Tokens (JWTs)
architect, critique, revise, codeModule 2: Credential Hygiene & Session Tokens (JWTs)
Goal: Load API configuration securely from the environment and issue cryptographically signed JWT login tokens.
What you need to know first
Credential Hygiene: Never commit secret keys, database passwords, or auth tokens to Git. If you push a secret key to GitHub, scanners will find it and compromise your system. Instead, store secrets in a local .env file that is excluded from Git, and load them at runtime.
- ⚠️ Environment Scope Warning: Putting secrets inside
.envdoes NOT load them into your local command-line shell session. If you typeecho $JWT_SECRETin your terminal, it will return blank. The.envfile variables are loaded exclusively into the memory of your running Python process when thepython-dotenvlibrary executes at script startup.
Stateful vs. Stateless Sessions (JWTs):
- Stateful (The List): In traditional setups, when a user logs in, the server registers the session in its database and keeps track of it. This is like a teacher maintaining a paper list of students allowed out of the room. Every time a student asks to go out, the teacher must read the list.
- Stateless (The Hall Pass): A JWT (JSON Web Token) acts like a digitally signed hall pass. When a user logs in successfully, the server creates a text ticket (the JWT) containing details like
user_idand an expiration timestamp. The server signs the pass using its secret key and hands it to the client. The client includes this pass on every request. The server doesn't need to consult a database list—it just verifies that the signature on the pass is valid and hasn't been forged.- A JWT has three dot-separated parts:
- Header: The type of token and hashing algorithm.
- Payload: The visible data (e.g. user ID, username, expiration time). Warning: anyone can decode the payload, so never store sensitive data like passwords inside it.
- Signature: The cryptographic proof verifying the token wasn't altered. It is signed using the secret key.
- A JWT has three dot-separated parts:
The SOLO idea
Before using JWTs, you must establish environment boundaries. Under Pillar 03: Security-First, setting up a .env file and updating .gitignore is a hard checkpoint before writing login routes. We use the planning loop to review the token's lifetime and verify it expires.
Lab 2: Safe Tokens
Estimated AI conversations: 3
- Install dependencies:
pip install python-dotenv pyjwt - Create a
.envfile in your project root:JWT_SECRET=generate_a_long_random_string_here - CRITICAL STEP: Add
.envto your.gitignorefile. Test it: rungit status. Verify that.envis not listed as an untracked file. - Load variables in
main.py:import os from dotenv import load_dotenv load_dotenv() JWT_SECRET = os.getenv("JWT_SECRET") - Step A: Plan login tokens. Open Copilot Chat and type:
Follow #file:workflows/architect.md — Plan a
POST /loginendpoint inmain.pythat acceptsusernameandpassword.- Query the SQLite
userstable to find the user. - Use
bcrypt.checkpw()to verify the password attempt against the database hash. - Plan to encode a JWT token containing payload keys
user_id,username, and an expiration timestamp (exp). Sign it withJWT_SECRET. - Return the token in JSON. If invalid, return a
401 Unauthorized.
- Query the SQLite
- Step B: Critique JWT payload. In the same conversation, type:
Follow #file:workflows/critique.md — Critique the token signing plan. Are we setting a sensible expiration interval? Are we leak-testing (e.g. making sure we don't accidentally embed the password hash in the JWT payload)?
- Step C: Revise.
Follow #file:workflows/revise.md — Revise the plan to set a token expiration of 1 hour, using standard UTC timestamps.
- Step D: Implement.
Follow #file:workflows/code.md — Implement the
/loginendpoint inmain.pybased on the plan. - Verify login via
curl:- Mac/Linux:
curl -i -X POST -H "Content-Type: application/json" -d '{"username": "testuser", "password": "mypassword"}' http://127.0.0.1:8000/login - Windows:
curl -i -X POST -H "Content-Type: application/json" -d "{\"username\": \"testuser\", \"password\": \"mypassword\"}" http://127.0.0.1:8000/login
access_tokenstring. - Mac/Linux:
- Commit:
git add . git commit -m "Module 2: JWT login token generation with environmental secrets" git push
Checkpoint
Create checkpoint_02.md:
- Verify your
.gitignorecontains.env. - Copy your login access token response and decode it using
jwt.io(or a decode script). Paste the payload parameters visible in the token.