Skip to content

Renew tokens via Firebase refresh token instead of replaying stored password#2

Open
dcaslin wants to merge 1 commit into
Alex-Keyes:mainfrom
dcaslin:fix/firebase-refresh-token
Open

Renew tokens via Firebase refresh token instead of replaying stored password#2
dcaslin wants to merge 1 commit into
Alex-Keyes:mainfrom
dcaslin:fix/firebase-refresh-token

Conversation

@dcaslin

@dcaslin dcaslin commented Jun 13, 2026

Copy link
Copy Markdown

Summary

Closes #1.

BoostcampAPI kept sessions alive by persisting the plaintext email + password and replaying them on a 403. This switches to the Firebase-native refresh-token flow, so the password is never written to disk.

Changes

  • Capture the refresh token. login() now keeps refreshToken from the Firebase sign-in response (previously discarded).
  • Add a refresh path. _refresh_session() POSTs grant_type=refresh_token to the Firebase secure-token endpoint (https://securetoken.googleapis.com/v1/token?key=<API_KEY>, reusing the existing FIREBASE_API_KEY) and adopts the returned id_token / refresh_token.
  • Use it on 403. _post()'s 403 handler now refreshes via the token grant first, retrying with the new token. Password re-login (_re_login()) is kept only as an in-memory fallback for credentials still held in the live process — it is never persisted.
  • Stop persisting the password. save_session() / load_session() now store {token, refresh_token} instead of {token, email, password}.

Design notes

  • I implemented reactive refresh (on 403) rather than proactive refresh via expiresIn, to mirror the existing retry structure and keep the change focused. expiresIn is available in the response if proactive renewal is wanted later.
  • Old session pickles (with email/password) still load — those keys are simply ignored. The first save_session() rewrites the file without the password.

Tests

Adds a pytest suite (the repo had none) covering token capture, session persistence excluding the password, the refresh exchange, and the 403 refresh-and-retry path. Tests use a small version-independent fake ClientSession (aioresponses doesn't track recent aiohttp releases).

$ pytest tests/ -q
6 passed

Run with pip install -r requirements-dev.txt && pytest.

🤖 Generated with Claude Code

Firebase ID tokens are short-lived; the client previously kept sessions
alive by persisting the plaintext email + password and replaying them on
a 403. This stores an unnecessary credential at rest and isn't how
Firebase is meant to refresh.

- Capture refreshToken from the login response
- Add _refresh_session() to exchange the refresh token at the Firebase
  secure-token endpoint for a fresh ID token
- _post()'s 403 handler now refreshes via the token grant first, falling
  back to password re-login only if credentials remain in memory
- save_session()/load_session() persist {token, refresh_token} and no
  longer write the plaintext password to disk

Adds a test suite (pytest) covering login capture, session persistence,
the refresh exchange, and the 403 refresh-and-retry path, using a small
version-independent fake ClientSession.

Closes Alex-Keyes#1

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
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.

Use Firebase refresh token for token renewal instead of replaying stored password

1 participant