Skip to content

Transparently recover from expired-JWT 401s (retry-on-401 + honest expiry) #146

Description

@zfarrell

Problem

A short-lived (300s) database-scoped access token reused just past its true exp can surface a spurious 401 {"error":"invalid_api_key"} to the caller, even though the credential is valid and re-minting immediately succeeds. Server-side extAuth now applies a 30s verification leeway (hotdata-dev/monopoly#1495), but the client has two gaps that should be closed independently so the SDK never propagates a recoverable auth blip:

  1. A 401 is treated as definitive and never retried. _is_transient_status excludes 4xx, and refresh only happens proactively when the cached token is within _LEEWAY (30s) of _exp. If the cached JWT is actually expired/near-expired when a request goes out, that request 401s and the error is surfaced to the user instead of the SDK transparently re-minting and retrying.

  2. Expiry is estimated as _exp = now + expires_in. If the mint endpoint returns a cached/stale expires_in, _exp runs ahead of the JWT's true exp, so the proactive _exp - _LEEWAY refresh fires too late and a past-exp token is sent on the wire.

Proposed change

  • On a 401 from an authenticated request, once per request: drop the cached JWT, force a fresh re-mint from the API token (not the refresh token), and retry the original request a single time. Never loop; a second 401 is a real rejection.
  • Derive the cached token's expiry from the minted JWT's own exp claim when present (fall back to expires_in). Keep — or slightly raise — the _LEEWAY margin.

Pointers

hotdata/_auth.py: _TokenManager, _LEEWAY, bearer_value, _is_transient_status, _mint.

Refs

  • Root-cause investigation: hotdata-dev/monopoly#1496
  • Server-side leeway fix: hotdata-dev/monopoly#1495
  • Prod signature: fast (~12ms) ext_authz_denied invalid_api_key on /v1/query + /v1/results, ~1/day, self-healing on next mint.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions