Skip to content

fix: stop retrying token rotation with an invalid refresh token - #679

Merged
mwbrooks merged 1 commit into
mainfrom
mwbrooks-fix-token-rotation-retry
Sep 29, 2026
Merged

mwbrooks merged 1 commit into
mainfrom
mwbrooks-fix-token-rotation-retry

Conversation

@mwbrooks

Copy link
Copy Markdown
Member

Changelog

Fixed an issue where an expired login with an invalid refresh token caused the CLI to retry token rotation on every command. The CLI now removes the invalid refresh token and asks you to run slack login again.

Summary

This pull request stops the CLI from repeatedly retrying token rotation when the stored refresh token is no longer valid.

  • When tooling.tokens.rotate returns invalid_refresh_token, the refresh token is removed from credentials.json and a warning asks you to run slack login. Before, the failure was only logged at debug level, so every command retried the rotation.
  • Rotation is attempted at most once per refresh token per process. This avoids repeated requests within a single command when rotation fails for other reasons, such as internal_error or network errors.
  • The API host is now restored when rotation fails. Before, it was only restored on success.

Preview

$ slack run

⚠️ Your credentials for 'my-workspace' have expired and can no longer be refreshed. Run `slack login` to authorize again.

Testing

  1. Log in with slack login.
  2. Set the exp for that auth in ~/.slack/credentials.json to a past timestamp:
    jq ".[\"<TEAM_ID>\"].exp = $(( $(date +%s) - 600 ))" ~/.slack/credentials.json > /tmp/c.json && mv /tmp/c.json ~/.slack/credentials.json
  3. Replace the refresh_token value with an invalid token, e.g. xoxe-1-invalid.
  4. Run slack auth list --verbose and confirm:
    • A single tooling.tokens.rotate request that returns invalid_refresh_token
    • The warning to run slack login
    • refresh_token is removed from ~/.slack/credentials.json
  5. Run slack auth list --verbose again and confirm no tooling.tokens.rotate request is made.
  6. Run slack login to restore a working auth.

Notes

  • Other codes such as internal_error are treated as transient: the refresh token is kept and rotation is retried in the next command, but only once per command.
  • Follow-up: activity --tail (and slack run activity polling) keeps polling after auth errors. That will be addressed in a separate PR.

Requirements

When tooling.tokens.rotate returns invalid_refresh_token, remove the
stored refresh token and warn to run slack login so rotation is not
retried on every command. Rotation is also attempted at most once per
refresh token per process, and the API host is restored when rotation
fails.
@mwbrooks mwbrooks added bug M-T: confirmed bug report. Issues are confirmed when the reproduction steps are documented semver:patch Use on pull requests to describe the release version increment labels Sep 28, 2026
@mwbrooks mwbrooks self-assigned this Sep 28, 2026
@mwbrooks mwbrooks added this to the Next Release milestone Sep 28, 2026
@codecov

codecov Bot commented Sep 28, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 78.22%. Comparing base (fcb0782) to head (950e5cb).
⚠️ Report is 2 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main     #679      +/-   ##
==========================================
+ Coverage   78.19%   78.22%   +0.03%     
==========================================
  Files         239      239              
  Lines       18132    18144      +12     
==========================================
+ Hits        14178    14193      +15     
+ Misses       3954     3951       -3     

☔ 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.

Comment thread internal/auth/auth.go
auth.RefreshToken = result.RefreshToken
auth.LastUpdated = time.Now()

// now restore the previous default apiHost

@mwbrooks mwbrooks Sep 28, 2026 •

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

note: This explicit restore only ran on the success path, so a failed rotation returned early and left the API host pointing at the auth's host. It's replaced by defer c.api.SetHost(activeAPIHostBeforeRotation) right after the host is captured, which restores the host on both success and error.

@mwbrooks
mwbrooks marked this pull request as ready for review September 28, 2026 23:40
@mwbrooks
mwbrooks requested a review from a team as a code owner September 28, 2026 23:40

@srtaalej srtaalej left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM works great!

@mwbrooks

Copy link
Copy Markdown
Member Author

Thanks for the quick reviews @srtaalej! 🙇🏻

@mwbrooks
mwbrooks merged commit 7076706 into main Sep 29, 2026
13 checks passed
@mwbrooks
mwbrooks deleted the mwbrooks-fix-token-rotation-retry branch September 29, 2026 21:44
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug M-T: confirmed bug report. Issues are confirmed when the reproduction steps are documented semver:patch Use on pull requests to describe the release version increment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants