Skip to content

fix: preserve existing refresh token when OAuth response omits it#1055

Open
Daryna Ishchenko (darynaishchenko) wants to merge 1 commit into
mainfrom
devin/1781794789-fix-missing-refresh-token
Open

fix: preserve existing refresh token when OAuth response omits it#1055
Daryna Ishchenko (darynaishchenko) wants to merge 1 commit into
mainfrom
devin/1781794789-fix-missing-refresh-token

Conversation

@darynaishchenko

@darynaishchenko Daryna Ishchenko (darynaishchenko) commented Jun 18, 2026

Copy link
Copy Markdown
Contributor

Summary

SingleUseRefreshTokenOauth2Authenticator.refresh_and_set_access_token() unconditionally overwrites the refresh token with whatever _extract_refresh_token() returns — including None when the OAuth provider omits refresh_token from the response.

This silently destroys the working refresh token and persists None into the connector config via the control message, causing all subsequent token refreshes to fail.

 def refresh_and_set_access_token(self) -> None:
     new_access_token, access_token_expires_in, new_refresh_token = self.refresh_access_token()
     self.access_token = new_access_token
-    self.set_refresh_token(new_refresh_token)
+    if new_refresh_token is not None:
+        self.set_refresh_token(new_refresh_token)
     self.set_token_expiry_date(access_token_expires_in)

Microsoft's /oauth2/v2.0/token endpoint typically returns a new refresh token when offline_access scope is requested, but this is not guaranteed by spec. Other OAuth providers (e.g., Google) intentionally omit the refresh token on refresh responses. The fix is defensive — keep the existing token when the response doesn't provide a replacement.

Link to Devin session: https://app.devin.ai/sessions/c87fd00904c446c6a38fc7313ca7b95c
Requested by: Daryna Ishchenko (@darynaishchenko)

Summary by CodeRabbit

  • Bug Fixes

    • OAuth authentication now gracefully handles scenarios where the OAuth provider omits the refresh token from the response, preserving the existing token while updating the access token and expiry.
  • Tests

    • Added test coverage for OAuth refresh flow when the provider does not return a refresh token.

Co-Authored-By: Daryna Ishchenko <darina.ishchenko17@gmail.com>
@devin-ai-integration

Copy link
Copy Markdown
Contributor

🤖 Devin AI Engineer

I'll be helping with this pull request! Here's what you should know:

✅ I will automatically:

  • Address comments on this PR. Add '(aside)' to your comment to have me ignore it.
  • Look at CI failures and help fix them

Note: I can only respond to comments from users who have write access to this repository.

⚙️ Control Options:

  • Disable automatic comment, CI, and merge conflict monitoring

@github-actions

Copy link
Copy Markdown

👋 Greetings, Airbyte Team Member!

Here are some helpful tips and reminders for your convenience.

💡 Show Tips and Tricks

Testing This CDK Version

You can test this version of the CDK using the following:

# Run the CLI from this branch:
uvx 'git+https://github.com/airbytehq/airbyte-python-cdk.git@devin/1781794789-fix-missing-refresh-token#egg=airbyte-python-cdk[dev]' --help

# Update a connector to use the CDK from this branch ref:
cd airbyte-integrations/connectors/source-example
poe use-cdk-branch devin/1781794789-fix-missing-refresh-token

PR Slash Commands

Airbyte Maintainers can execute the following slash commands on your PR:

  • /autofix - Fixes most formatting and linting issues
  • /poetry-lock - Updates poetry.lock file
  • /test - Runs connector tests with the updated CDK
  • /prerelease - Triggers a prerelease publish with default arguments
  • /poe build - Regenerate git-committed build artifacts, such as the pydantic models which are generated from the manifest JSON schema in YAML.
  • /poe <command> - Runs any poe command in the CDK environment
📚 Show Repo Guidance

Helpful Resources

📝 Edit this welcome message.

@darynaishchenko Daryna Ishchenko (darynaishchenko) marked this pull request as ready for review June 18, 2026 15:03
@coderabbitai

coderabbitai Bot commented Jun 18, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: f4535d97-d25b-4af6-b617-32fb8240f299

📥 Commits

Reviewing files that changed from the base of the PR and between 626c753 and 721fce9.

📒 Files selected for processing (2)
  • airbyte_cdk/sources/streams/http/requests_native_auth/oauth.py
  • unit_tests/sources/streams/http/requests_native_auth/test_requests_native_auth.py

📝 Walkthrough

Walkthrough

SingleUseRefreshTokenOauth2Authenticator.refresh_access_token return type changed from Tuple[str, AirbyteDateTime, str] to Tuple[str, AirbyteDateTime, Optional[str]]. refresh_and_set_access_token now only overwrites the stored refresh token when the provider response includes one; otherwise the existing token is preserved. A new unit test covers this behavior.

Changes

Optional Refresh Token Handling in SingleUseRefreshTokenOauth2Authenticator

Layer / File(s) Summary
Optional refresh token contract and conditional persistence
airbyte_cdk/sources/streams/http/requests_native_auth/oauth.py, unit_tests/sources/streams/http/requests_native_auth/test_requests_native_auth.py
refresh_access_token return type updated to Tuple[str, AirbyteDateTime, Optional[str]]; refresh_and_set_access_token conditionally persists the refresh token only when the provider returns a non-None value; new test asserts access token updates while original refresh token is preserved when omitted from response.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~8 minutes

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately and concisely summarizes the main change: preserving the existing refresh token when OAuth providers omit it from responses, which directly addresses the core problem and solution described in the PR objectives.
Docstring Coverage ✅ Passed Docstring coverage is 80.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch devin/1781794789-fix-missing-refresh-token

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions

Copy link
Copy Markdown

PyTest Results (Fast)

4 119 tests  +1   4 108 ✅ +1   8m 33s ⏱️ +12s
    1 suites ±0      11 💤 ±0 
    1 files   ±0       0 ❌ ±0 

Results for commit 721fce9. ± Comparison against base commit 626c753.

@github-actions

Copy link
Copy Markdown

PyTest Results (Full)

4 122 tests  +1   4 110 ✅ +1   12m 18s ⏱️ +11s
    1 suites ±0      12 💤 ±0 
    1 files   ±0       0 ❌ ±0 

Results for commit 721fce9. ± Comparison against base commit 626c753.

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.

2 participants