fix: allow Slack reauthorization after saved credential failures

Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
DottaandPaperclip committed 2026-10-06 21:50:17 -05:00
1 parent bcd12a046c
commit e3bb642933
4 files changed
+17 -8

No files matched your search

+1 -1
View File
@@ -67,7 +67,7 @@ the browser cannot supply a manifest, scopes, or callback destination.
| Creation uncertain after timeout/restart | Inspect Slack app settings. Recover an existing app manually on this draft. Start another creation only after explicitly confirming that no app exists. |
| App created; installation declined/pending | Install the saved app again. No configuration token is needed. |
| Authorization expired or code exchange uncertain | Start fresh installation authorization. Used codes are never replayed. |
| Credentials saved; connection check failed | Use Retry connecting. Paperclip reuses vaulted credentials. |
| Credentials saved; connection check failed | Use Retry connecting. Paperclip reuses vaulted credentials. If Slack access changed or the token was revoked, use Authorize in Slack again for the same app. |
| Wrong app/workspace/bot or missing scopes | Correct the installation of this app. Activation remains blocked. |
| Removed connection | Pending state and app-registration secrets are invalidated. Remove the customer's app separately through its Slack management link if desired. |
@@ -74,5 +74,9 @@ describe("automatic Slack setup actions", () => {
api.resumeSlackInstallation.mockResolvedValue(saved);
click("Retry connecting"); await settle();
expect(api.resumeSlackInstallation).toHaveBeenCalledWith("endpoint"); expect(api.createSlackApp).not.toHaveBeenCalled();
api.installSlackApp.mockRejectedValue(new Error("Authorization unavailable"));
click("Authorize in Slack again"); await settle();
expect(api.installSlackApp).toHaveBeenCalledWith("endpoint");
expect(api.createSlackApp).not.toHaveBeenCalled();
});
});
+11 -6
View File
@@ -72,6 +72,12 @@ export function SlackAutomaticSetup({ endpoint, stage, disabled, saveDetails, on
} finally { token = ""; }
}
async function authorize() {
const result = await chatEndpointsApi.installSlackApp(endpoint.id);
// Current-tab navigation avoids popup blockers. The callback resumes this saved draft.
window.location.assign(result.authorizationUrl);
}
return <div className="space-y-5">
{error || registration?.errorCode ? <p role="alert" className="text-sm text-destructive">
{error ?? slackRegistrationErrorMessage(registration!.errorCode!)}
@@ -101,7 +107,10 @@ export function SlackAutomaticSetup({ endpoint, stage, disabled, saveDetails, on
{stage === "credentials" && " Approve its installation in Slack. Paperclip will save the credentials and continue here automatically."}
{registration?.managementUrl && <> <a className="underline underline-offset-4" href={registration.managementUrl} target="_blank" rel="noopener noreferrer">Open Slack app settings <ExternalLink className="inline size-3" /></a></>}
</p>}
{stage === "credentials" && registration?.status === "credentials_saved" && <p className="text-sm text-muted-foreground">Your installation credentials are saved. Retry connecting to finish setup.</p>}
{stage === "credentials" && registration?.status === "credentials_saved" && <div className="space-y-2">
<p className="text-sm text-muted-foreground">Your installation credentials are saved. Retry connecting to finish setup. If Slack access has changed, authorize the same app again.</p>
<Button variant="link" className="h-auto p-0" disabled={busy || disabled} onClick={() => void run(authorize)}>Authorize in Slack again</Button>
</div>}
{stage === "app" && <div className="flex flex-wrap gap-4 text-sm">
<Button variant="link" className="h-auto p-0" disabled={busy || creating} onClick={() => void run(() => onManual(false))}>Create manually</Button>
<Button variant="link" className="h-auto p-0" disabled={busy || creating} onClick={() => void run(() => onManual(true))}>Use an existing app</Button>
@@ -112,11 +121,7 @@ export function SlackAutomaticSetup({ endpoint, stage, disabled, saveDetails, on
{busy && <Loader2 className="size-4 animate-spin" />}{created ? "Continue to installation" : "Create Slack app"}
</Button> : registration?.status === "credentials_saved" ? <Button disabled={busy} onClick={() => void run(async () => onSaved(await chatEndpointsApi.resumeSlackInstallation(endpoint.id)))}>
{busy && <Loader2 className="size-4 animate-spin" />}Retry connecting
</Button> : <Button disabled={busy || !created || disabled} onClick={() => void run(async () => {
const result = await chatEndpointsApi.installSlackApp(endpoint.id);
// Current-tab navigation avoids popup blockers. The callback resumes this saved draft.
window.location.assign(result.authorizationUrl);
})}>
</Button> : <Button disabled={busy || !created || disabled} onClick={() => void run(authorize)}>
{busy ? <Loader2 className="size-4 animate-spin" /> : <ExternalLink className="size-4" />}Install in Slack
</Button>}
</SetupWizardFooter>
+1 -1
View File
@@ -14,7 +14,7 @@ Ask me to take over for login, two-factor authentication, CAPTCHA, workspace-adm
3. Create Slack app automatically. Review Slack app name, Bot display name, and Slash command in Paperclip. Keep the generated defaults unless I requested other names. Use the automatic setup path for a new bot. Ask me to open Slack's Your App Configuration Tokens > Generate Token, select the agreed workspace, and enter the temporary configuration token directly into Paperclip's App configuration token password field. Pause while I do that. Never read, copy, reveal, screenshot, or include that token in your prompt or tool output. Do not request its refresh token. Click Create Slack app after I enter it. Paperclip creates the app and saves its signing secret itself. Its saved state is the evidence of creation; a click or navigation is not proof. Resume the matching draft after refresh or Save & exit. If creation is uncertain, open Slack app settings and check the agreed workspace for the exact app before continuing. Never retry creation automatically. Only confirm that no app was created after I explicitly confirm that check, or recover the existing app on this same draft. No Slack CLI is required.
4. Install Slack app. Use Install in Slack for the app Paperclip created. Check the workspace and approve installation within the agreed scope. Pause for required login, ownership decisions, or administrator approval. Return to the saved wizard through Slack's OAuth redirect. Paperclip obtains and saves the bot token itself; do not locate, copy, or request the bot token or signing secret on the automatic path. Wait for Paperclip to report saved credentials and open Verify Slack connection. If approval is declined or pending, preserve the app and resume its installation later without another configuration token. If authorization expires, start a fresh installation of this same app. If credentials are saved but connecting fails, use Retry connecting. Do not recreate the app. Never link the installing Slack user to a Paperclip account automatically.
4. Install Slack app. Use Install in Slack for the app Paperclip created. Check the workspace and approve installation within the agreed scope. Pause for required login, ownership decisions, or administrator approval. Return to the saved wizard through Slack's OAuth redirect. Paperclip obtains and saves the bot token itself; do not locate, copy, or request the bot token or signing secret on the automatic path. Wait for Paperclip to report saved credentials and open Verify Slack connection. If approval is declined or pending, preserve the app and resume its installation later without another configuration token. If authorization expires, start a fresh installation of this same app. If credentials are saved but connecting fails, use Retry connecting. If Slack access changed or the token was revoked, use Authorize in Slack again for this same app. Do not recreate the app. Never link the installing Slack user to a Paperclip account automatically.
Manual fallback only when selected or needed for recovery: choose Create manually or Use an existing app on the creation step. For manual creation, use Paperclip's generated manifest, select the agreed workspace in Slack, and install that exact app. Preserve all scopes, bot events, slash command, interactivity, and signed HTTP callbacks. For an existing app, reconcile its configuration with this connection's manifest and generated URLs. Have me enter the Bot User OAuth Token (OAuth & Permissions, xoxb- prefix) and Signing Secret (Basic Information > App Credentials) directly into the matching Paperclip fields, or use safe clipboard transfer only as described above. The Signing Secret is not the Client Secret, Verification Token, or app-level token. Click Connect Slack app. On a resumed manual setup, leave credential fields blank to keep saved values. Never use Socket Mode as a shortcut.