Skip to content

Periodic cleanup of expired OAuth2 tokens#11530

Draft
pieterbeulque wants to merge 1 commit into
mainfrom
claude/investigate-ai-auth-flow-MtgWW
Draft

Periodic cleanup of expired OAuth2 tokens#11530
pieterbeulque wants to merge 1 commit into
mainfrom
claude/investigate-ai-auth-flow-MtgWW

Conversation

@pieterbeulque
Copy link
Copy Markdown
Contributor

@pieterbeulque pieterbeulque commented May 8, 2026

(sorry, this shouldn't've created a PR, but wanted to ask if this is something we should/could/need to do?)

Summary

The MCP "create product with AI" flow exchanges the user's session for a 1h OAuth2 access token via the custom web grant on every cache miss (cookie cached for expires_in seconds). The grant doesn't issue a refresh token, so each issuance is a brand-new row in oauth2_tokens, and there's no job that ever deletes them — OAuth2TokenService.get_by_access_token only checks is_expired() at lookup time, leaving expired rows behind forever.

This adds a daily cron actor that prunes safely-deletable expired tokens, mirroring the existing pattern from customer_session.delete_expired and auth.delete_expired.

What gets deleted

A row is deleted only if all of the following hold:

  1. The access token is past expiry: issued_at + expires_in < now() (expires_at is a Python property, not a column, so the SQL has to expand it).
  2. There is no usable refresh path: refresh_token IS NULL OR refresh_token_revoked_at != 0. This preserves third-party OAuth apps that still have a valid refresh token they could use to mint a new access token.
  3. The token's client_id is not the legacy Polar app client (APP_CLIENT_ID). The service intentionally accepts expired tokens from that client as a temporary workaround for an unfixed mobile auth flow — deleting those rows would break the workaround.

Files

  • server/polar/oauth2/repository.py (new) — OAuth2TokenRepository.delete_expired(*, exclude_client_ids).
  • server/polar/oauth2/service/oauth2_token.pyOAuth2TokenService.delete_expired wires the APP_CLIENT_ID exclusion.
  • server/polar/oauth2/tasks.py (new) — oauth2_token.delete_expired cron actor (hour=0, minute=0, TaskPriority.LOW, max_retries=0).
  • server/polar/tasks.py — registers the new tasks module.
  • server/tests/oauth2/service/test_oauth2_token.pyTestDeleteExpired covering the four cases above.

Test plan

  • CI runs TestDeleteExpired (local execution blocked by a pre-existing Python 3.14rc2 / pydantic-ai import failure in this sandbox; ruff passes on all touched files).
  • After deploy, confirm the cron actor appears in the scheduler logs at 00:00 UTC and that oauth2_tokens row count stops growing for client_id values without refresh tokens.

https://claude.ai/code/session_01LJttmtBWXZwktjxLRJnHpt


Generated by Claude Code

The MCP "create product with AI" flow uses a custom web grant that issues
short-lived (1h) OAuth2 access tokens but no refresh token, so the
oauth2_tokens table accumulated rows that were never deleted. Add a daily
cron actor that prunes tokens whose access has expired and which either
have no refresh token or whose refresh token has been revoked, so
third-party OAuth apps with active refresh paths are preserved. Tokens
issued to the legacy Polar app client are also excluded to keep the
existing expired-token workaround intact.
@pieterbeulque pieterbeulque requested review from a team and frankie567 as code owners May 8, 2026 18:47
@vercel
Copy link
Copy Markdown

vercel Bot commented May 8, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
polar Ready Ready Preview, Comment May 8, 2026 6:50pm
polar-sandbox Ready Ready Preview, Comment May 8, 2026 6:50pm

Request Review

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 8, 2026

OpenAPI Changes

No changes detected in the OpenAPI schema.

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 8, 2026

Preview Environment
URL: https://polar-preview-vm.taildbff7b.ts.net/pr-11530
API: https://polar-preview-vm.taildbff7b.ts.net/pr-11530/v1/
Logs: backend
SHA: f9b8d10aff124cd4ac80a3cc8957bd24859ce320

@pieterbeulque pieterbeulque marked this pull request as draft May 8, 2026 19:49
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.

3 participants