Skip to content

Fix Slack OAuth refresh recovery after lost responses - #236

Merged
aseembits93 merged 3 commits into
mainfrom
fix/slack-refresh-idempotency
Aug 27, 2026
Merged

Fix Slack OAuth refresh recovery after lost responses#236
aseembits93 merged 3 commits into
mainfrom
fix/slack-refresh-idempotency

Conversation

@aseembits93

Copy link
Copy Markdown
Collaborator

Summary

  • refresh Slack credentials five minutes before recorded expiry instead of using a one-minute safety window
  • route opaque Slack refresh handles through a per-handle Durable Object that coalesces concurrent requests
  • persist the successful response in encrypted form before returning it and replay it for ten minutes when a client response is lost
  • reduce replayed expires_in by elapsed time so clients retain the provider's real expiry
  • document the new broker state, security boundary, and Cloudflare migration

Why

Slack refresh tokens are single-use. Previously, if Slack accepted a rotation but the response was lost between the broker and Locality, the replacement pair was never saved and every retry reused the consumed token. The broker then surfaced an unrecoverable 502 and required reconnection.

Tests

  • npm run check in apps/oauth-service (37 tests)
  • npx wrangler deploy --dry-run --outdir /tmp/locality-slack-refresh-worker-build-final
  • cargo fmt --all -- --check
  • cargo test -p locality-slack
  • cargo test -p localityd --test source_descriptor slack -- --test-threads=1
  • git diff --check

Existing unrelated checks

cargo clippy -p locality-slack --all-targets -- -D warnings remains blocked by pre-existing Clippy warnings in locality-core and existing Slack hosted/settings files. A full unfiltered source_descriptor run also hit existing Google Docs failures and a stopped-broker timeout; all Slack-filtered cases pass.

@vercel

vercel Bot commented Aug 26, 2026

Copy link
Copy Markdown

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

Project Deployment Actions Updated (UTC)
locality Ready Ready Preview Aug 26, 2026 8:05pm

@github-actions

Copy link
Copy Markdown

Codex review

  • major: apps/oauth-service/src/app.ts:377 keys the Durable Object by the raw refresh_token_handle string after validation, but handle parsing currently accepts aliases like valid_handle.extra because only the first three .-separated parts are used. Those aliases decrypt to the same Slack refresh token but route to different Durable Objects, so concurrent or retried requests can bypass coalescing/replay and consume Slack’s single-use refresh token twice, leaving the client without the rotated token. Minimal fix: reject handles with any extra segments in the handle decoder, or route by a canonical validated key; add a test that validHandle + ".suffix" is rejected or maps to the same coordinator.

@aseembits93
aseembits93 merged commit e81999c into main Aug 27, 2026
7 of 11 checks passed
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.

1 participant