Skip to content

fix: add token expiry and timing-safe password check#23

Open
ankushchk wants to merge 1 commit intoalphaonelabs:mainfrom
ankushchk:fix/token-expiry-and-timing-safe-password
Open

fix: add token expiry and timing-safe password check#23
ankushchk wants to merge 1 commit intoalphaonelabs:mainfrom
ankushchk:fix/token-expiry-and-timing-safe-password

Conversation

@ankushchk
Copy link
Copy Markdown

@ankushchk ankushchk commented Mar 26, 2026

Summary

  • Add 1-hour expiry (exp claim) to auth tokens, previously tokens never expired
  • Switch verify_password() from == to hmac.compare_digest() to prevent timing attacks
  • Rename shadowed variable exp to expected in verify_token() for clarity

What was wrong

  1. Tokens lived forever - create_token() had no exp field and verify_token() never checked expiration. A leaked token would grant permanent access.
  2. Timing-unsafe password check - hash_password(password, username) == stored leaks information about how many characters matched via response time differences.

Test plan

  • Login returns token with exp field (base64-decode payload to verify)
  • Fresh token works on /api/dashboard
  • Expired token (crafted with past exp) is rejected with "Authentication required"
  • Existing login/register flows still work

Purpose

This PR implements two critical security improvements to the authentication system: token expiration to limit the window of exposure for leaked credentials, and timing-safe password verification to prevent timing attacks that could leak password information.

Key Modifications

  1. Token Expiration: Added 1-hour (_TOKEN_TTL = 3600) expiry to all authentication tokens via a new exp claim in the token payload. The verify_token() function now validates this claim and rejects expired tokens.

  2. Timing-Safe Password Comparison: Replaced direct string equality (==) with hmac.compare_digest() in verify_password() to provide constant-time comparison and prevent attackers from leveraging response timing to infer password information.

  3. Code Clarity: Renamed the ambiguous exp variable to expected in verify_token() to avoid shadowing the exp claim from the token payload.

Impact

  • Security: Tokens granted through compromised credentials now have limited utility (1-hour window), and password verification no longer exposes timing side-channels.
  • Functionality: Existing login and registration flows remain compatible; authentication still succeeds for valid, non-expired tokens. Users will need to re-authenticate after 1 hour of token issue.
  • Code Quality: Improved variable naming for clarity in token validation logic.

Verification

The changes have been verified with existing login/register flows, token expiration validation (fresh tokens authorize access, expired tokens are rejected), and normal operation of the authentication system.

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Mar 26, 2026

Walkthrough

Authentication and authorization security enhancements added to src/worker.py. Token creation now includes expiration claims with a 3600-second TTL. Password and token signature verification switched to constant-time comparison using HMAC to mitigate timing attacks. Token verification now rejects expired tokens based on the expiration claim.

Changes

Cohort / File(s) Summary
Token & Authentication Security
src/worker.py
Added token expiration support (_TOKEN_TTL = 3600), updated create_token() to include exp claim, hardened verify_password() with constant-time comparison via _hmac.compare_digest(), and enhanced verify_token() to validate expiration and use constant-time signature comparison.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 33.33% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title directly and clearly summarizes the two main security improvements: adding token expiry and implementing timing-safe password verification.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/worker.py`:
- Around line 195-196: The token validation currently allows tokens lacking an
"exp" claim to pass; update the check so tokens without exp are rejected and
expired tokens are rejected too by replacing the condition with a strict
requirement (e.g., use data.get("exp") presence check and compare
int(data["exp"]) against int(time.time())); specifically change the conditional
around data, exp and time.time() such that if not data.get("exp") or
int(data["exp"]) < int(time.time()): return None, ensuring the validator returns
None for missing or expired exp values (optionally log a warning before
rejecting for migration scenarios).
- Around line 178-179: The function verify_token lacks a return type annotation;
update its signature to include a precise return type such as Optional[Dict[str,
Any]] (or dict | None for Python 3.10+) to reflect "decoded payload dict or
None", and add the required typing imports (Optional, Dict, Any) at the top if
not already present so static checkers and readers can understand the return
value; keep the existing docstring but ensure the signature reads e.g. def
verify_token(raw: str, secret: str) -> Optional[Dict[str, Any]]:.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository: alphaonelabs/coderabbit/.coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: d3b84fce-c3d1-4a5c-a4fc-579c87bae777

📥 Commits

Reviewing files that changed from the base of the PR and between a08bafc and 13194fb.

📒 Files selected for processing (1)
  • src/worker.py

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