Skip to content

Recover from a rejected refresh token by logging in again#39

Merged
bforma merged 1 commit into
mainfrom
recover-from-rejected-refresh-token-with-relogin
Jun 4, 2026
Merged

Recover from a rejected refresh token by logging in again#39
bforma merged 1 commit into
mainfrom
recover-from-rejected-refresh-token-with-relogin

Conversation

@bforma

@bforma bforma commented Jun 4, 2026

Copy link
Copy Markdown
Contributor

Lost het 401-stormpatroon op dat we in productie zagen op het gedeelde Easee-account (Sentry stekker#2017): bij een afgewezen refresh-token logt de client nu opnieuw in met username/wachtwoord in plaats van te blijven hangen op 401's.

Aanleiding

Sentry stekker#2017: Connections::ChargePointConnection::RequestFailed: status 401 op GET /api/chargers/{id}/state, ~800 events over één account met meerdere laders, in bursts van ~3 tegelijk per refresh-cyclus. Productie-console bevestigde: de credentials zijn geldig (verse login werkt), en het herstelde zichzelf pas zodra de cache-token verliep.

Root cause

Easee refresh-tokens zijn single-use en sessie-gebonden (changelog). Wanneer meerdere requests voor hetzelfde account tegelijk een 401 krijgen, racen ze op dezelfde refresh-token: de "verliezers" hergebruiken een al-verbruikte token, die Easee afwijst en die de sessie kan opruimen. De oude with_error_handling deed één refresh en gaf het daarna op (Errors::RequestFailed), waardoor elke poll 401 bleef geven tot de gecachte token verliep (uren) — vandaar de storm.

Easee's eigen advies hierbij: "Fall back to username/password authentication when token refresh fails."

Wijziging

with_error_handling herauthenticeert nu één keer en geeft daarna pas op. De herauthenticatie (reauthenticate!) probeert eerst een refresh en valt bij een afgewezen refresh terug op een volledige login (request_access_token). Daardoor herstelt de client zich op de volgende call i.p.v. te blijven loopen op 401's.

  • Een login die faalt met ongeldige credentials blijft een InvalidCredentials opleveren (zodat de caller een echt ongeldig account nog steeds kan loskoppelen).
  • Niet-401 fouten (rate limit, 403, 5xx) behouden hun bestaande gedrag.

Reproductie

spec/easee/client_spec.rb:

  • "logs in with username and password when the refresh token is rejected" — refresh faalt → login slaagt → request herstelt; faalde vóór de wijziging met RequestFailed.
  • "raises InvalidCredentials when the refresh fails and re-login is rejected" — echt ongeldige credentials blijven InvalidCredentials.

Vervolg

Na merge moet StekkerWeb de gem bumpen (bundle update stekker_easee, die github: "stekker/easee", branch: "main" volgt) om de fix in productie te krijgen. Een per-account lock om de gelijktijdige re-logins verder te beperken kan eventueel later in StekkerWeb via job-serialisatie — niet nodig voor correctheid, want de re-login fallback voorkomt de aanhoudende storm.

Easee refresh tokens are single-use and session-linked. When several
requests for the same account hit a 401 at once, they race on the same
refresh token; the losers reuse a consumed token, which Easee rejects
and which can tear down the session. The previous handler gave up after
one failed refresh, so every poll kept returning 401 until the cached
token expired (hours), flooding error tracking.

Reauthentication now falls back to a full username/password login when
the refresh is rejected, as Easee's own guidance recommends, so the
client recovers on the next call instead of looping on 401s. A login
that fails with invalid credentials still surfaces as InvalidCredentials.
@bforma bforma merged commit 14e516d into main Jun 4, 2026
1 check passed
@bforma bforma deleted the recover-from-rejected-refresh-token-with-relogin branch June 4, 2026 07:58
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