fix: preserve hello-ok scopes for reused device tokens (#68039)

This commit is contained in:
Val Alexander
2026-04-17 03:20:48 -05:00
committed by GitHub
parent f377db1015
commit be7a415eb0
2 changed files with 65 additions and 1 deletions

View File

@@ -270,6 +270,69 @@ export function registerDefaultAuthTokenSuite(): void {
}
});
test("hello-ok reports persisted token scopes when reusing an existing device token", async () => {
const { randomUUID } = await import("node:crypto");
const os = await import("node:os");
const path = await import("node:path");
const token = resolveGatewayTokenOrEnv();
const deviceIdentityPath = path.join(
os.tmpdir(),
`openclaw-shared-auth-scope-reuse-${randomUUID()}.json`,
);
const wsInitial = await openWs(port);
let pairedDeviceToken: string | undefined;
let pairedDeviceScopes: unknown;
try {
const initial = await connectReq(wsInitial, {
token,
scopes: ["operator.admin"],
deviceIdentityPath,
});
expect(initial.ok).toBe(true);
const helloOk = initial.payload as
| {
auth?: {
role?: unknown;
scopes?: unknown;
deviceToken?: unknown;
};
}
| undefined;
expect(helloOk?.auth?.role).toBe("operator");
expect(Array.isArray(helloOk?.auth?.scopes)).toBe(true);
expect(typeof helloOk?.auth?.deviceToken).toBe("string");
pairedDeviceToken = helloOk?.auth?.deviceToken as string | undefined;
pairedDeviceScopes = helloOk?.auth?.scopes;
} finally {
wsInitial.close();
}
const wsReconnect = await openWs(port);
try {
const reconnect = await connectReq(wsReconnect, {
token,
scopes: ["operator.read"],
deviceIdentityPath,
});
expect(reconnect.ok).toBe(true);
const helloOk = reconnect.payload as
| {
auth?: {
role?: unknown;
scopes?: unknown;
deviceToken?: unknown;
};
}
| undefined;
expect(helloOk?.auth?.role).toBe("operator");
expect(helloOk?.auth?.deviceToken).toBe(pairedDeviceToken);
expect(helloOk?.auth?.scopes).toEqual(pairedDeviceScopes);
expect(helloOk?.auth?.scopes).not.toEqual(["operator.read"]);
} finally {
wsReconnect.close();
}
});
test("does not grant admin when scopes are omitted", async () => {
const ws = await openWs(port);
const token = resolveGatewayTokenOrEnv();

View File

@@ -1217,6 +1217,7 @@ export function attachGatewayWsMessageHandler(params: {
canvasHostUrl && canvasCapability
? (buildCanvasScopedHostUrl(canvasHostUrl, canvasCapability) ?? canvasHostUrl)
: canvasHostUrl;
const helloOkAuthScopes = deviceToken ? deviceToken.scopes : scopes;
const helloOk = {
type: "hello-ok",
protocol: PROTOCOL_VERSION,
@@ -1229,7 +1230,7 @@ export function attachGatewayWsMessageHandler(params: {
canvasHostUrl: scopedCanvasHostUrl,
auth: {
role,
scopes,
scopes: helloOkAuthScopes,
...(deviceToken
? {
deviceToken: deviceToken.token,