Skip to content

fix: backdate JWT iat to avoid clock-skew 401s#64

Merged
itsmeadi merged 2 commits into
masterfrom
fix/jwt-iat-clock-skew
Jun 10, 2026
Merged

fix: backdate JWT iat to avoid clock-skew 401s#64
itsmeadi merged 2 commits into
masterfrom
fix/jwt-iat-clock-skew

Conversation

@itsmeadi

@itsmeadi itsmeadi commented Jun 10, 2026

Copy link
Copy Markdown
Collaborator

Summary

Backdate the JWT iat claim on server auth tokens by a few seconds so tokens are never stamped ahead of the server clock.

iat is a whole-second value (RFC 7519 NumericDate), so Time.now.to_i truncates to the second. With no safety margin, a caller whose clock is marginally ahead of the server can intermittently get token used before issue at (iat) (HTTP 401) when the truncation lands on a second boundary. Backdating iat by Client::AUTH_IAT_LEEWAY_SECONDS (5s) keeps it safely in the past.

Changes

  • Client#generate_auth_header: stamp iat: Time.now.to_i - AUTH_IAT_LEEWAY_SECONDS.
  • Add spec/auth_token_spec.rb asserting iat is backdated and never ahead of "now".
  • CHANGELOG entry under [Unreleased] / Fixed.

Test plan

  • bundle exec rspec spec/auth_token_spec.rb
  • Full unit suite
  • RuboCop clean on changed files

The server auth token stamped `iat = Time.now.to_i`. Because `iat` is a
whole-second value (RFC 7519 NumericDate) and the server applies minimal
forward leeway, a small fraction of requests were rejected with
"token used before issue at (iat)" (HTTP 401) whenever the caller's clock
was marginally ahead of the server and the second-truncation landed on a
boundary. Observed at ~0.03% of requests, spread uniformly across all
caller hosts.

Backdate `iat` by Client::AUTH_IAT_LEEWAY_SECONDS (5s) so the token is
always safely behind the server clock. The legacy stream-chat-ruby client
never sent `iat`, which is why upgrades from it newly exposed this.

Co-authored-by: Cursor <cursoragent@cursor.com>
Fixes Lint/UselessConstantScoping: `private` does not affect constants,
so the constant is declared at the top of the class instead.

Co-authored-by: Cursor <cursoragent@cursor.com>
@itsmeadi itsmeadi merged commit 0e1bdc9 into master Jun 10, 2026
7 checks passed
@itsmeadi itsmeadi deleted the fix/jwt-iat-clock-skew branch June 10, 2026 19:26
github-actions Bot added a commit that referenced this pull request Jun 10, 2026
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