Skip to content

Stop refreshing when the fresh token is rejected, and surface the 401 reason - #369

Open
wit3 wants to merge 1 commit into
omniphx:masterfrom
wit3:fix/jwt-refresh-recursion
Open

wit3 wants to merge 1 commit into
omniphx:masterfrom
wit3:fix/jwt-refresh-recursion

Conversation

@wit3

@wit3 wit3 commented Oct 28, 2026

Copy link
Copy Markdown

Fixes #367. Related: #334.

Client::request() refreshes on any 401 and retries. During authenticate() the resource listing is fetched with the token just obtained, so if Salesforce rejects that token (e.g. a Connected App without the api scope → INVALID_SCOPES) the 401 triggers refresh() → authenticate() again, and the process recurses until it runs out of memory.

  • request() now refreshes at most once: a 401 raised while a refresh is in progress is rethrown instead of starting another one.
  • The 401 response body is included in the TokenExpiredException message, so the actual reason (INVALID_SCOPES, INVALID_SESSION_ID, …) is visible. Note: code matching the exact message string Salesforce token has expired would need to use str_starts_with.

Adds a regression test for the OAuthJWT flow that fails without the fix.

This touches the same lines in request() as #365; the two changes are independent and the conflict is trivial.

… reason

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

This branch has not been deployed

No deployments
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.

OAuthJWT: a 401 from storeResources() during authenticate() recurses forever (memory exhausted), and leaves a token cached without resources

1 participant