fix: refresh endpoint uses refresh-token header, not body#7
Merged
Conversation
tryRefresh() was POSTing the refresh JWT in a JSON body field, which the
backend rejects with a pydantic 422 ("missing header"). The error was
swallowed by the try/catch, so callers saw the original 401 propagated
through with no indication that the refresh attempt had even happened -
effectively treating every access-token expiry (~12h) as a forced
re-login.
Fixed by sending the token as a `refresh-token` HTTP header, matching
what the Flutter app does (confirmed via the reverse-engineered Dart
disassembly: pp+0x9180 "refresh-token"). With this fix the session
survives until the refresh token itself expires, ~30 days.
Also updates CLOUD_API.md and openapi.yaml to document the actual
header-based contract. Bumps version to 0.5.1.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
`tryRefresh()` was POSTing the refresh JWT in a JSON body field. The Flappie backend reads it from a `refresh-token` HTTP header — body submission returns a pydantic 422 (`missing header`) which the try/catch in `tryRefresh()` swallowed silently. End user effect: every ~12h the access token expires and the next call returns 401 to the caller with no automatic recovery, so it looks like `flappie login` is needed on a daily basis.
Fix
Send the token as a `refresh-token` HTTP header. Confirmed against the live API and via the Dart disassembly (`pp+0x9180 "refresh-token"`).
Tested locally: `flappie whoami` recovers without re-login when the access token is expired.
Also in this PR
After merge
This will be the first end-to-end test of the release automation: push `v0.5.1` tag → `.github/workflows/release.yml` runs → `npm publish --provenance` via OIDC → GitHub Release page auto-created.