feat(openclaw): Ed25519 device auth for full scoped gateway access#462
feat(openclaw): Ed25519 device auth for full scoped gateway access#462Steven17D wants to merge 1 commit intoasheshgoplani:mainfrom
Conversation
The OpenClaw gateway strips operator scopes from connections without cryptographic device identity. This adds proper Ed25519 device authentication to the OpenClaw client: - Generate and persist Ed25519 keypair (~/.agent-deck/openclaw/device.json) - Derive deviceId from SHA256(raw_public_key) - Sign v3 auth payloads (deviceId|clientId|mode|role|scopes|ts|token|nonce|platform|family) - Include signed device identity in every connect handshake - Persist device tokens from hello-ok responses - Request all operator scopes (admin, read, write, approvals, pairing) - Send auth token in both token and password fields - Add `agent-deck openclaw pair` command for explicit pairing workflow
b2bdefc to
1569a90
Compare
asheshgoplani
left a comment
There was a problem hiding this comment.
The Ed25519 device auth concept is sound, but there are security issues that need attention before this can ship.
Critical:
-
Password in both Token AND Password fields.
sendConnect()setsAuth.Token = c.passwordandAuth.Password = c.password. This doubles the credential surface in the wire payload. TheTokenfield is semantically different (JWT-style); sending the raw password there may cause the server to attempt two auth paths and leaks the password into a field that may be logged differently server-side. Remove one. -
Device token never becomes the primary credential. The signed payload in
BuildDeviceConnect()is bound to the shared gateway secret (authToken = c.password). Even after pairing and receiving adeviceToken, the handshake is still authenticated by the long-lived shared password. Revoking/rotating the device token doesn't de-privilege the client. For "Ed25519 device auth," the device key should be the primary credential after pairing, not a supplement to the shared secret. -
LoadOrCreateIdentityfails open on corrupt state. IfderiveDeviceIDfails,derivedis the zero value, but the code writesid.DeviceID = derivedand continues. Corruption/tampering ofdevice.jsonshould stop the flow and return an error, not silently "heal" into an invalid identity.
Important:
-
Private key stored as plaintext JSON.
PrivateKeyPEMis written directly to~/.agent-deck/openclaw/device.jsonwith no encryption. Consider OS keychain integration or at minimum document this prominently. -
Non-atomic file writes.
os.WriteFiletruncates and rewrites in place. If killed mid-write, the identity file is corrupted. Use write-to-temp +os.Rename()for atomic writes. -
Server nonce not validated.
waitForChallenge()passes the nonce directly toBuildDeviceConnect()with no length/format check. A malicious gateway could supply an empty nonce enabling signature replay. Reject nonces shorter than 16 bytes. -
No token expiry.
DeviceTokenRefhasUpdatedAtMsbut noExpiresAtMs. Tokens are stored indefinitely. -
No test coverage for device auth paths. Existing tests only cover password auth.
The cryptographic primitives are correctly chosen (Ed25519, SHA256, PKCS8/PKIX PEM). The issues are in credential handling and state management.
asheshgoplani
left a comment
There was a problem hiding this comment.
Checking back on this, @Steven17D. The 8 security and quality issues from the previous review remain unaddressed, and no follow-up commits have been pushed.
Please revisit the earlier review comments and push updates. Happy to re-review once those items are addressed.
|
Closing: 8 security/quality issues remain unaddressed (plaintext keys, missing nonce validation, no tests, etc). The OpenClaw device auth concept needs upstream coordination. Feel free to resubmit when the gateway side is ready. Thanks @Steven17D! |
Summary
agent-deck openclaw paircommand for device registrationTest plan
agent-deck openclaw pair, verify device identity is createdagent-deck openclaw pair --idshows device ID🤖 Generated with Claude Code