Skip to content

Commit ab13d8f

Browse files
authored
bridge: require registration token for broker registration (#111)
1 parent 092d302 commit ab13d8f

7 files changed

Lines changed: 42 additions & 46 deletions

File tree

AGENTS.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,7 @@ sudo baudbot update
127127
sudo baudbot rollback previous
128128

129129
# Register a server with Slack broker (after OAuth callback)
130-
sudo baudbot broker register --broker-url https://broker.example.com --workspace-id T0123ABCD --auth-code <code>
130+
sudo baudbot broker register --broker-url https://broker.example.com --workspace-id T0123ABCD --registration-token <token>
131131

132132
# Rotate an API key after setup (prompts hidden input)
133133
sudo baudbot env set ANTHROPIC_API_KEY --restart
@@ -146,7 +146,7 @@ tmux new-window -n baudbot 'sudo -u baudbot_agent ~/runtime/start.sh'
146146
## Slack broker pull-mode notes
147147

148148
- Broker delivery is now pull-based. Registration is callback-free:
149-
- `sudo baudbot broker register --broker-url ... --workspace-id T... --auth-code ...`
149+
- `sudo baudbot broker register --broker-url ... --workspace-id T... --registration-token ...`
150150
- After a successful broker registration, always restart to load new keys:
151151
- `sudo baudbot restart`
152152
- The runtime starts `broker-bridge.mjs` automatically when `SLACK_BROKER_*` vars are present.

CONFIGURATION.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ If you're using the Slack broker OAuth flow, register this server after install:
4949
sudo baudbot broker register \
5050
--broker-url https://your-broker.example.com \
5151
--workspace-id T0123ABCD \
52-
--auth-code <auth-code-from-oauth-callback>
52+
--registration-token <token-from-dashboard-callback>
5353
```
5454

5555
`baudbot setup` is host provisioning only; do not use `baudbot setup --slack-broker`.

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ Slack broker registration (after OAuth callback). When `SLACK_BROKER_*` variable
9595
sudo baudbot broker register \
9696
--broker-url https://your-broker.example.com \
9797
--workspace-id T0123ABCD \
98-
--auth-code <auth-code-from-oauth-callback>
98+
--registration-token <token-from-dashboard-callback>
9999
```
100100

101101
Need to rotate/update a key later?

bin/baudbot

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -421,11 +421,11 @@ case "${1:-}" in
421421
exec "$NODE_BIN" "$BAUDBOT_ROOT/bin/broker-register.mjs" "$@"
422422
;;
423423
--help|-h|"")
424-
echo "Usage: sudo baudbot broker register [--broker-url URL] [--workspace-id ID] [--auth-code CODE] [-v|--verbose]"
424+
echo "Usage: sudo baudbot broker register [--broker-url URL] [--workspace-id ID] --registration-token TOKEN [-v|--verbose]"
425425
;;
426426
*)
427427
echo "Unknown broker subcommand: ${1:-}"
428-
echo "Usage: sudo baudbot broker register [--broker-url URL] [--workspace-id ID] [--auth-code CODE] [-v|--verbose]"
428+
echo "Usage: sudo baudbot broker register [--broker-url URL] [--workspace-id ID] --registration-token TOKEN [-v|--verbose]"
429429
exit 1
430430
;;
431431
esac

bin/broker-register.mjs

Lines changed: 11 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
* Registers this baudbot server with a Slack broker workspace using:
66
* - broker URL
77
* - workspace ID
8-
* - one-time auth code from OAuth callback
8+
* - registration token from dashboard callback
99
*
1010
* On success, stores broker config and generated server key material in:
1111
* - admin config: ~/.baudbot/.env
@@ -47,8 +47,7 @@ export function usageText() {
4747
"Options:",
4848
" --broker-url URL Broker base URL (e.g. https://broker.example.com)",
4949
" --workspace-id ID Slack workspace ID (e.g. T0123ABCD)",
50-
" --registration-token TOKEN 10-minute registration token from dashboard callback",
51-
" --auth-code CODE Legacy one-time auth code (fallback)",
50+
" --registration-token TOKEN Registration token from dashboard callback (required)",
5251
" -v, --verbose Show detailed registration progress",
5352
" -h, --help Show this help",
5453
"",
@@ -61,7 +60,6 @@ export function parseArgs(argv) {
6160
brokerUrl: "",
6261
workspaceId: "",
6362
registrationToken: "",
64-
authCode: "",
6563
verbose: false,
6664
help: false,
6765
};
@@ -109,15 +107,6 @@ export function parseArgs(argv) {
109107
continue;
110108
}
111109

112-
if (arg.startsWith("--auth-code=")) {
113-
out.authCode = arg.slice("--auth-code=".length);
114-
continue;
115-
}
116-
if (arg === "--auth-code") {
117-
i++;
118-
out.authCode = argv[i] || "";
119-
continue;
120-
}
121110

122111
throw new Error(`unknown argument: ${arg}`);
123112
}
@@ -215,18 +204,15 @@ export async function fetchBrokerPubkeys(brokerUrl, fetchImpl = fetch) {
215204

216205
export function mapRegisterError(status, errorText) {
217206
const text = String(errorText || "request failed");
207+
if (status === 400 && /missing registration proof/i.test(text)) {
208+
return "registration token is required";
209+
}
218210
if (status === 403 && /invalid registration token/i.test(text)) {
219211
return "invalid registration token — re-run OAuth install and use a fresh token";
220212
}
221213
if (status === 403 && /registration token already used/i.test(text)) {
222214
return "registration token already used — re-run OAuth install and use a fresh token";
223215
}
224-
if (status === 403 && /invalid auth code/i.test(text)) {
225-
return "invalid auth code — re-run OAuth install and use the new auth code";
226-
}
227-
if (status === 403 && /auth code already consumed/i.test(text)) {
228-
return "auth code already consumed — re-install the Slack app to get a fresh code";
229-
}
230216
if (status === 409 && /already active/i.test(text)) {
231217
return "workspace already active — unregister the current server first";
232218
}
@@ -285,7 +271,6 @@ export async function registerWithBroker({
285271
brokerUrl,
286272
workspaceId,
287273
registrationToken,
288-
authCode,
289274
serverKeys,
290275
fetchImpl = fetch,
291276
logger = () => {},
@@ -298,8 +283,7 @@ export async function registerWithBroker({
298283
workspace_id: workspaceId,
299284
server_pubkey: serverKeys.server_pubkey,
300285
server_signing_pubkey: serverKeys.server_signing_pubkey,
301-
...(registrationToken ? { registration_token: registrationToken } : {}),
302-
...(authCode ? { auth_code: authCode } : {}),
286+
registration_token: registrationToken,
303287
};
304288

305289
logger(`Registering workspace ${workspaceId} at ${endpoint}`);
@@ -536,18 +520,16 @@ async function collectInputs(parsedArgs) {
536520
|| existing.SLACK_BROKER_WORKSPACE_ID
537521
|| (await prompt("Workspace ID (starts with T): "));
538522

539-
const registrationToken = parsedArgs.registrationToken || (await prompt("Registration token (leave blank to use auth code): "));
540-
const authCode = parsedArgs.authCode || (!registrationToken ? (await prompt("Auth code (legacy): ")) : "");
523+
const registrationToken = parsedArgs.registrationToken || (await prompt("Registration token: "));
541524

542-
if (!registrationToken && !authCode) {
543-
throw new Error("registration token or auth code is required");
525+
if (!registrationToken) {
526+
throw new Error("registration token is required");
544527
}
545528

546529
return {
547530
brokerUrl: normalizeBrokerUrl(brokerUrl),
548531
workspaceId: workspaceId.trim(),
549532
registrationToken,
550-
authCode,
551533
configTargets,
552534
};
553535
}
@@ -556,16 +538,15 @@ export async function runRegistration({
556538
brokerUrl,
557539
workspaceId,
558540
registrationToken,
559-
authCode,
560541
fetchImpl = fetch,
561542
logger = () => {},
562543
}) {
563544
if (!validateWorkspaceId(workspaceId)) {
564545
throw new Error("workspace ID must match Slack team ID format (e.g. T0123ABCD)");
565546
}
566547

567-
if (!registrationToken && !authCode) {
568-
throw new Error("registration token or auth code is required");
548+
if (!registrationToken) {
549+
throw new Error("registration token is required");
569550
}
570551

571552
const normalizedBrokerUrl = normalizeBrokerUrl(brokerUrl);
@@ -576,7 +557,6 @@ export async function runRegistration({
576557
brokerUrl: normalizedBrokerUrl,
577558
workspaceId,
578559
registrationToken,
579-
authCode,
580560
serverKeys,
581561
fetchImpl,
582562
logger,

bin/broker-register.test.mjs

Lines changed: 24 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -36,15 +36,14 @@ test("parseArgs parses long-form options", () => {
3636
"https://broker.example.com/",
3737
"--workspace-id",
3838
"T123ABC",
39-
"--auth-code",
40-
"secret-code",
39+
"--registration-token",
40+
"token-xyz",
4141
]);
4242

4343
assert.deepEqual(parsed, {
4444
brokerUrl: "https://broker.example.com/",
4545
workspaceId: "T123ABC",
46-
registrationToken: "",
47-
authCode: "secret-code",
46+
registrationToken: "token-xyz",
4847
verbose: false,
4948
help: false,
5049
});
@@ -85,6 +84,10 @@ test("parseArgs rejects unknown arguments", () => {
8584
assert.throws(() => parseArgs(["--wat"]), /unknown argument/);
8685
});
8786

87+
test("parseArgs rejects legacy auth-code argument", () => {
88+
assert.throws(() => parseArgs(["--auth-code", "legacy"]), /unknown argument/);
89+
});
90+
8891
test("validation helpers normalize and enforce broker/workspace formats", () => {
8992
assert.equal(normalizeBrokerUrl("https://broker.example.com/"), "https://broker.example.com");
9093
assert.equal(validateWorkspaceId("T0ABC123"), true);
@@ -94,7 +97,8 @@ test("validation helpers normalize and enforce broker/workspace formats", () =>
9497
});
9598

9699
test("mapRegisterError returns actionable messages", () => {
97-
assert.match(mapRegisterError(403, "invalid auth code"), /invalid auth code/);
100+
assert.match(mapRegisterError(400, "missing registration proof"), /registration token is required/);
101+
assert.match(mapRegisterError(403, "invalid registration token"), /invalid registration token/);
98102
assert.match(mapRegisterError(409, "workspace already active"), /already active/);
99103
assert.match(mapRegisterError(500, "oops"), /broker server error/);
100104
});
@@ -117,7 +121,8 @@ test("registerWithBroker fetches pubkeys then posts registration payload", async
117121
assert.equal(payload.workspace_id, "TTEST123");
118122
assert.equal(payload.server_pubkey, FIXTURE_SERVER_KEYS.server_pubkey);
119123
assert.equal(payload.server_signing_pubkey, FIXTURE_SERVER_KEYS.server_signing_pubkey);
120-
assert.equal(payload.auth_code, "one-time-code");
124+
assert.equal(payload.registration_token, "token-abc");
125+
assert.equal(payload.auth_code, undefined);
121126
assert.equal(payload.server_callback_url, undefined);
122127

123128
return jsonResponse({
@@ -133,7 +138,7 @@ test("registerWithBroker fetches pubkeys then posts registration payload", async
133138
const result = await registerWithBroker({
134139
brokerUrl: "https://broker.example.com",
135140
workspaceId: "TTEST123",
136-
authCode: "one-time-code",
141+
registrationToken: "token-abc",
137142
serverKeys: FIXTURE_SERVER_KEYS,
138143
fetchImpl,
139144
});
@@ -212,11 +217,12 @@ test("runRegistration integration path succeeds against live local HTTP server",
212217
const result = await runRegistration({
213218
brokerUrl,
214219
workspaceId: "TABC12345",
215-
authCode: "auth-code-from-oauth",
220+
registrationToken: "token-from-dashboard",
216221
});
217222

218223
assert.ok(receivedRegisterPayload);
219224
assert.equal(receivedRegisterPayload.workspace_id, "TABC12345");
225+
assert.equal(receivedRegisterPayload.registration_token, "token-from-dashboard");
220226
assert.equal(receivedRegisterPayload.server_callback_url, undefined);
221227
assert.ok(result.updates.SLACK_BROKER_SERVER_PRIVATE_KEY);
222228
assert.ok(result.updates.SLACK_BROKER_SERVER_SIGNING_PRIVATE_KEY);
@@ -227,6 +233,16 @@ test("runRegistration integration path succeeds against live local HTTP server",
227233
}
228234
});
229235

236+
test("runRegistration requires registration token", async () => {
237+
await assert.rejects(
238+
runRegistration({
239+
brokerUrl: "https://broker.example.com",
240+
workspaceId: "TABC12345",
241+
}),
242+
/registration token is required/,
243+
);
244+
});
245+
230246
test("upsertEnvContent updates existing values and appends new ones", () => {
231247
const existing = [
232248
"SLACK_BOT_TOKEN=xoxb-old",

docs/operations.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ sudo baudbot env sync --restart
6363
sudo baudbot broker register \
6464
--broker-url https://your-broker.example.com \
6565
--workspace-id T0123ABCD \
66-
--auth-code <auth-code-from-oauth-callback>
66+
--registration-token <token-from-dashboard-callback>
6767
```
6868

6969
Do not use `baudbot setup --slack-broker``setup` is host provisioning only.

0 commit comments

Comments
 (0)