openclaw gateway: persist device keys on create/update and clarify pairing flow
This commit is contained in:
@@ -267,8 +267,11 @@ POST /api/companies/$CLA_COMPANY_ID/invites
|
||||
- default path: `adapterConfig.disableDeviceAuth` is false/absent and stable `adapterConfig.devicePrivateKeyPem` is set so approvals persist across runs
|
||||
- fallback path: `disableDeviceAuth=true` only for environments that cannot support pairing
|
||||
5. Trigger one connectivity run. If it returns `pairing required`, approve the pending device request in OpenClaw and retry once.
|
||||
- Note: Paperclip invite approval and OpenClaw device-pairing approval are separate gates.
|
||||
- Local docker automation path:
|
||||
- `openclaw devices approve --latest --json --url ws://127.0.0.1:18789 --token <gateway-token>`
|
||||
- Optional inspection:
|
||||
- `openclaw devices list --json --url ws://127.0.0.1:18789 --token <gateway-token>`
|
||||
- After approval, retries should succeed using the persisted `devicePrivateKeyPem`.
|
||||
6. Claim API key with `claimSecret`.
|
||||
7. Save claimed token to OpenClaw expected file path (`~/.openclaw/workspace/paperclip-claimed-api-key.json`) and ensure `PAPERCLIP_API_KEY` + `PAPERCLIP_API_URL` are available for OpenClaw skill execution context.
|
||||
|
||||
@@ -22,6 +22,7 @@ type GatewayDeviceIdentity = {
|
||||
deviceId: string;
|
||||
publicKeyRawBase64Url: string;
|
||||
privateKeyPem: string;
|
||||
source: "configured" | "ephemeral";
|
||||
};
|
||||
|
||||
type GatewayRequestFrame = {
|
||||
@@ -486,6 +487,7 @@ function resolveDeviceIdentity(config: Record<string, unknown>): GatewayDeviceId
|
||||
deviceId: crypto.createHash("sha256").update(raw).digest("hex"),
|
||||
publicKeyRawBase64Url: base64UrlEncode(raw),
|
||||
privateKeyPem: configuredPrivateKey,
|
||||
source: "configured",
|
||||
};
|
||||
}
|
||||
|
||||
@@ -497,6 +499,7 @@ function resolveDeviceIdentity(config: Record<string, unknown>): GatewayDeviceId
|
||||
deviceId: crypto.createHash("sha256").update(raw).digest("hex"),
|
||||
publicKeyRawBase64Url: base64UrlEncode(raw),
|
||||
privateKeyPem,
|
||||
source: "ephemeral",
|
||||
};
|
||||
}
|
||||
|
||||
@@ -912,6 +915,14 @@ export async function execute(ctx: AdapterExecutionContext): Promise<AdapterExec
|
||||
|
||||
try {
|
||||
const deviceIdentity = disableDeviceAuth ? null : resolveDeviceIdentity(parseObject(ctx.config));
|
||||
if (deviceIdentity) {
|
||||
await ctx.onLog(
|
||||
"stdout",
|
||||
`[openclaw-gateway] device auth enabled keySource=${deviceIdentity.source} deviceId=${deviceIdentity.deviceId}\n`,
|
||||
);
|
||||
} else {
|
||||
await ctx.onLog("stdout", "[openclaw-gateway] device auth disabled\n");
|
||||
}
|
||||
|
||||
await ctx.onLog("stdout", `[openclaw-gateway] connecting to ${parsedUrl.toString()}\n`);
|
||||
|
||||
@@ -1076,7 +1087,7 @@ export async function execute(ctx: AdapterExecutionContext): Promise<AdapterExec
|
||||
const timedOut = lower.includes("timeout");
|
||||
const pairingRequired = lower.includes("pairing required");
|
||||
const detailedMessage = pairingRequired
|
||||
? `${message}. Configure adapterConfig.disableDeviceAuth=true for smoke/dev, or set adapterConfig.devicePrivateKeyPem so pairing persists across runs.`
|
||||
? `${message}. Approve the pending device in OpenClaw (for example: openclaw devices approve --latest --url <gateway-ws-url> --token <gateway-token>) and retry. Ensure this agent has a persisted adapterConfig.devicePrivateKeyPem so approvals are reused.`
|
||||
: message;
|
||||
|
||||
await ctx.onLog("stderr", `[openclaw-gateway] request failed: ${detailedMessage}\n`);
|
||||
|
||||
Reference in New Issue
Block a user