Skip to content

feat: harden the install callback (full redirect_uri, no exchange without a code, optional state check) - #56

Merged
johnkors merged 3 commits into
mainfrom
jk/oauth-callback-hardening
Nov 2, 2026
Merged

johnkors merged 3 commits into
mainfrom
jk/oauth-callback-hardening

Conversation

@johnkors

@johnkors johnkors commented Nov 2, 2026 •

Copy link
Copy Markdown
Contributor
  • Endpoint routing: the install callback now works mapped as an endpoint, not only with app.Map, because redirect_uri is the callback's full URL (PathBase + Path); app.Map users get the same URL as before
  • Declined installs: a callback without a code (?error=access_denied) never exchanges anything; the new OAuthOptions.CancelledRedirectUri sends it to the app's page with its state and Slack's error (so the page can tell a cancel from a failure), and left unset the request goes on to the next middleware as before
  • Forged callbacks: the new OAuthOptions.ValidateState checks state before the code is exchanged or Install runs, so a stray or forged callback installs nothing
  • Failures: a refused state, or a code Slack refuses, goes to the new OAuthOptions.FailedRedirectUri instead of a 500 with Slack's error text
  • All opt-in: without the new options the middleware behaves as today; tests in OAuthCallbackTests

…hout a code, an optional state check

- redirect_uri is the callback's PathBase plus Path, so the middleware works mounted as an endpoint as well as with app.Map
- a callback without a code never exchanges; OAuthOptions.CancelledRedirectUri takes a declined install to the app's page
- OAuthOptions.ValidateState runs before the exchange; a refused state, or a code Slack refuses, goes to FailedRedirectUri (a bare 403 or 500 without one)
@johnkors
johnkors merged commit 11f5adb into main Nov 2, 2026
1 of 2 checks passed
@johnkors
johnkors deleted the jk/oauth-callback-hardening branch November 2, 2026 13:55
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