Skip to content

feat(standardized-auth): add an acme sample for standardized app auth - #305

Draft
WilliamBergamin wants to merge 14 commits into
mainfrom
standardized-auth
Draft

WilliamBergamin wants to merge 14 commits into
mainfrom
standardized-auth

Conversation

@WilliamBergamin

@WilliamBergamin WilliamBergamin commented Oct 16, 2026 •

Copy link
Copy Markdown
Contributor

Summary

This pull request adds a standardized-auth sample: Acme, an app that connects user accounts with the Slack-owned Connect and Manage connection controls. Rocket skates, anvils, and giant magnets not included.

  • Bolt's installation store is the source of truth: a user is connected when it holds their user token.
  • The OAuth success hook reports a new connection with apps.user.connection.requestAuth, which also redraws an open auth modal, and refreshes App Home.
  • Disconnect forgets the user token, reports the user as disconnected, then revokes the token; tokens_revoked forgets users who remove the app.
  • user_connection_status_requested is answered with apps.user.connection.update.
  • App Home renders the auth_provider block.
  • Each listener file registers itself with @app.action or @app.event, and app.py imports every file under src/listeners at startup, so a new listener only needs a new file.
  • The user_connection listener, for the Connect on the app profile, is registered, but it won't fire until Bolt routes the user_connection payload to .action listeners.
  • Pins slack_sdk to python-slack-sdk main by commit until the next release.

Testing

In a workspace where standardized app authentication is available:

  1. Run ngrok http 3000 and replace 1234-56-78-90-0.ngrok-free.app in manifest.json.
  2. Run slack install --environment local, then slack env init with the client ID, client secret, signing secret, and your ngrok URL as BASE_URL.
  3. Run slack run and open https://<ngrok host>/slack/install to install the app.
  4. Open the app's Home tab and confirm the "Acme account" row shows Connected as @you.
  5. Click Disconnect and confirm the row shows Connect and the user token is revoked.
  6. Click Connect, approve in the new tab, and confirm the row shows Connected again.
  7. Remove the app's access in your Slack settings and confirm App Home shows Connect.

🤖 Generated with Claude Code

WilliamBergamin and others added 14 commits October 16, 2026 12:22
Connects user accounts with the Slack-owned Connect and Manage connection
controls. Bolt's installation store holds each connection: the OAuth success
hook reports it with apps.user.connection.requestAuth, the disconnect
action forgets and revokes the user token, tokens_revoked forgets users
who remove the app, and the user_connection_status_requested event is
answered with apps.user.connection.update. App Home renders the
auth_provider block.

The user_connection request listener is written and tested but not yet
registered, since no Bolt routes that payload to action listeners yet.
Resolves the conflict with #306, which replaced test.yml with ci.yml.
Adds standardized-auth to the lint, typecheck, and test matrices.

Co-Authored-By: Claude <svc-devxp-claude@slack-corp.com>
OAuth state no longer needs files on disk. The state is now an HMAC-signed
token checked with the signing secret, and it expires after 5 minutes because
a stateless token can be replayed until then. Installations stay in the file
store so connections survive a restart.

Co-Authored-By: Claude <svc-devxp-claude@slack-corp.com>
… helpers

Split the listeners into src/listeners/{events,actions,oauth}/, one file per
handler, following the bolt-python-starter-template layout. Replace the
AcmeAccounts and AcmeListeners classes, the Connection dataclass, and the
action ID constants with plain functions in src/acme.py, and use a single
App Home greeting. Tests mirror the new layout.

Co-Authored-By: Claude <svc-devxp-claude@slack-corp.com>
Each listener file now registers itself with @app.action or @app.event,
so its id sits next to its callback. app.py imports every file under
src/listeners at startup, replacing the hand-written register functions,
and the user_connection listener is registered too.

Co-Authored-By: Claude <svc-devxp-claude@slack-corp.com>
… bolt_app.py

Renaming src/app.py to src/bolt_app.py leaves one module named app, the
entry point. The OAuth success and failure callbacks are arguments to
OAuthSettings rather than listeners, so they now live next to the App
they configure, and src/listeners holds only self-registering listeners.

Co-Authored-By: Claude <svc-devxp-claude@slack-corp.com>
Loading the listener directory where the app is built means any import
of the app comes with every listener registered, and app.py is left as
a plain entry point.

Co-Authored-By: Claude <svc-devxp-claude@slack-corp.com>
…package

The loader builds each module name from the listeners directory and
the package bolt_app.py lives in, so no project root path is needed.

Co-Authored-By: Claude <svc-devxp-claude@slack-corp.com>
Co-Authored-By: Claude <svc-devxp-claude@slack-corp.com>
Co-Authored-By: Claude <svc-devxp-claude@slack-corp.com>
Walking the listeners package by module name reads more plainly than
building names from file paths.

Co-Authored-By: Claude <svc-devxp-claude@slack-corp.com>
Co-Authored-By: Claude <svc-devxp-claude@slack-corp.com>
…tion on forget

Deleting only the per-user installer files left the revoked user token in
the workspace's latest installation. Bolt's authorize then ran auth.test on
that token for the disconnected user and dropped their next request. Saving
the installation without the user token updates both files.

Co-Authored-By: Claude <svc-devxp-claude@slack-corp.com>
The default success page sends org-wide installs to the admin page for
adding workspaces. A user who clicked Connect should land back in the
app's Home tab, so the success callback now redirects there.

Co-Authored-By: Claude <svc-devxp-claude@slack-corp.com>
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