{
  "id": 1905900,
  "title": "The Login Loop of Doom.",
  "url": "https://urgent.news/2026/08/19/the-login-loop-of-doom",
  "topic": "tech",
  "section": "Tech",
  "published": "2026-08-19T09:47:29.000Z",
  "source": {
    "name": "Dev.to",
    "slug": "dev-to",
    "url": "https://dev.to/georgejnrs/the-login-loop-of-doom-how-a-naive-datetime-held-our-users-hostage-4cmm"
  },
  "original_language": "en",
  "account": "The \"Login Loop of Doom\" is a tale of a developer who encountered a frustrating issue with authentication in their app. Auth0's Universal Login page appeared, and the user entered their credentials, only to be redirected back to the login page again and again. The login loop seemed endless, and no error messages or failed login attempts were displayed. Auth0 was happily authenticating the user, but the app was bouncing the user back to the login page repeatedly, like a bouncer checking IDs and then forgetting the check.\n\nInitially, the developer suspected the frontend callback handler code, but tests revealed that the frontend was working correctly. They then suspected Auth0 misconfiguration, but Auth0's token lifetime and other details were correct. The root cause was found in the custom JWT validation middleware, where the `exp` (expiration time) claim was compared against the local server time instead of UTC. Since the server was several hours ahead of UTC, the tokens were always marked as expired, causing a 401 error from Django, which the frontend treated as a session expiration and redirected to Auth0, creating an infinite login loop.\n\nTo fix the issue, the developer modified the middleware to compare the expiration time against UTC time instead of the local server time. Additionally, the frontend was updated to handle 401 errors differently, distinguishing between a rejected token and an expired session. The developer then verified the fix by testing the login flow with different accounts, login methods, and session states. The lesson learned was that always using `datetime.now(timezone.utc)` for anything that touches timestamps, tokens, or comparisons across systems is crucial. It's also important to distinguish between failure modes to prevent small bugs from becoming infinite loops. Testing should be done like an attacker to uncover hidden issues.",
  "summary": "This is a submission for DEV's Summer Bug Smash: Smash Stories powered by Sentry . Code snippets are recreated and anonymized for illustrative purposes. The Symptom: A Revolving Door Instead of a Login Page It started innocently enough: I was clicking through our app and hit \"Log in.\" Auth0's Universal Login page appeared, I entered my credentials, got redirected back to the app... and landed on…",
  "key_points": [
    "Developer encountered endless login loop with Auth0 Universal Login page",
    "Custom JWT validation middleware compared exp claim to local server time, not UTC",
    "Fix involved comparing expiration time against UTC and handling 401 errors differently"
  ],
  "editors_take": null,
  "illustration": null,
  "coverage": {
    "outlets": 1,
    "also_reported_by": []
  },
  "ai_generated": true,
  "disclaimer": "Summaries, key points and the editor’s take are written by software from other outlets’ reporting and may contain errors — always check the linked original."
}