Skip to content

fix(bitbucket): treat a rejected refresh token as a dead grant - #2172

Merged
nijel merged 3 commits into
python-social-auth:masterfrom
amritghimire:fix/bitbucket-dead-refresh-token
Nov 2, 2026
Merged

nijel merged 3 commits into
python-social-auth:masterfrom
amritghimire:fix/bitbucket-dead-refresh-token

Conversation

@amritghimire

Copy link
Copy Markdown
Contributor

We hit this after upgrading to social-core 6. A background job that refreshes Bitbucket tokens started getting dead grants as provider errors and cancelled logins instead of credential errors, so it never asked those users to reconnect. We're keeping a small workaround in our app until this lands.

Bitbucket doesn't answer a dead refresh token with OAuth's invalid_grant. A revoked token gets a 400 (Atlassian community thread):

{"error_description": "Invalid refresh_token", "error": "invalid_request"}

The token of a deactivated Atlassian account gets a 401 "User is inactive" (AX-684). Its error code is one that provider_error treats as a user cancellation. So today the first raises AuthProviderError (http_error) and the second raises AuthCanceled. Code that asks the user to reconnect on AuthCredentialError can't tell either one from an outage or a cancelled login.

This can't go into provider_error the way bad_refresh_token did in #2124. invalid_request and the cancellation codes are generic, and at login a cancellation code really does mean the user cancelled. So BitbucketOAuth2.refresh_token now turns a 400 invalid_request, or a cancellation with status 401, into AuthCredentialError with reauthentication_required. There's no user in the loop during a refresh, so a cancellation there means Bitbucket refused the account.

Every other refresh error raises as before. That includes a 401 with no error code, which can also mean the client credentials were rejected. The new tests cover both rejections, and check that a plain-text 401, an invalid_client 400 and a 503 keep their current errors. The two rejection tests fail without the change. The full suite, prek, pyright, mypy, ty and pylint pass locally.

Sources:

Bitbucket doesn't use invalid_grant when it rejects a refresh token. A
revoked token comes back as a 400 invalid_request "Invalid refresh_token".
The token of a deactivated Atlassian account comes back as a 401 "User is
inactive", with a code that provider_error reads as a cancellation. So
these raised AuthProviderError and AuthCanceled, and apps couldn't tell
them apart from an outage or a cancelled login.

BitbucketOAuth2.refresh_token now raises AuthCredentialError with
reauthentication_required for exactly these two responses. Both codes are
generic, so this lives in the Bitbucket backend at the refresh stage
instead of in provider_error. A 401 without an error code still raises as
before, since it can also mean the client credentials were rejected.
@nijel

nijel commented Nov 2, 2026

Copy link
Copy Markdown
Member

@codex review

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Nov 2, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-11-02T12:52:47.630076Z ac80380 Manual request
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. You're on a roll.

Reviewed commit: 9c81757920

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@nijel

nijel commented Nov 2, 2026

Copy link
Copy Markdown
Member

Can you please look into failing tests?

@nijel nijel self-assigned this Nov 2, 2026
Upstream now reads invalid_request as a configuration error, so the
try/except around refresh_token no longer saw Bitbucket's 400 "Invalid
refresh_token" and the refresh tests failed. Moving the check into the
get_provider_error hook classifies both the revoked token and the
inactive user at the point the HTTP error is built, whatever the base
classification turns into.
@nijel

nijel commented Nov 2, 2026

Copy link
Copy Markdown
Member

@codex review

@codecov

codecov Bot commented Nov 2, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 97.18%. Comparing base (5afd033) to head (ac80380).
⚠️ Report is 5 commits behind head on master.

Additional details and impacted files
@@            Coverage Diff             @@
##           master    #2172      +/-   ##
==========================================
+ Coverage   97.16%   97.18%   +0.01%     
==========================================
  Files         374      376       +2     
  Lines       23666    23808     +142     
  Branches     1448     1452       +4     
==========================================
+ Hits        22996    23138     +142     
  Misses        466      466              
  Partials      204      204              
Flag Coverage Δ
unittests 97.18% <100.00%> (+0.01%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Bravo.

Reviewed commit: ac80380ab6

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@nijel
nijel merged commit 3d482a6 into python-social-auth:master Nov 2, 2026
19 checks passed
@nijel

nijel commented Nov 2, 2026

Copy link
Copy Markdown
Member

Merged, thanks for your contribution!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

2 participants