henrygd/beszel · error

invalid signature - check KEY value

Error message

invalid signature - check KEY value

What it means

During the auth challenge, the hub sends a challenge that the client signs with its private key; verifySignature verifies the returned signature (or signs and verifies the token) against the KEY-derived public key. If no signature scheme succeeds (pubKey.Verify fails for the token), the library concludes the key/token combination is wrong and throws this error. It does not necessarily mean the wire data is corrupt — most often the configured KEY does not correspond to the token or the hub's expectation.

Source

Thrown at agent/client.go:250

		serverAddr := client.agent.connectionManager.serverOptions.Addr
		_, response.Port, _ = net.SplitHostPort(serverAddr)
	}

	return client.sendResponse(response, requestID)
}

// verifySignature verifies the signature of the token using the public keys.
func (client *WebSocketClient) verifySignature(signature []byte) (err error) {
	for _, pubKey := range client.agent.keys {
		sig := ssh.Signature{
			Format: pubKey.Type(),
			Blob:   signature,
		}
		if err = pubKey.Verify([]byte(client.token), &sig); err == nil {
			return nil
		}
	}
	return errors.New("invalid signature - check KEY value")
}

// Close closes the WebSocket connection gracefully.
// This method is safe to call multiple times.
func (client *WebSocketClient) Close() {
	if client.Conn != nil {
		_ = client.Conn.WriteClose(1000, nil)
	}
}

// handleHubRequest routes the request to the appropriate handler using the handler registry.
func (client *WebSocketClient) handleHubRequest(msg *common.HubRequest[cbor.RawMessage], requestID *uint32) error {
	ctx := &HandlerContext{
		Client:       client,
		Agent:        client.agent,
		Request:      msg,
		RequestID:    requestID,
		HubVerified:  client.hubVerified,

View on GitHub (pinned to b38fb7dafa)

Solutions

  1. Regenerate/confirm that KEY and TOKEN were issued together from the hub and paste the full untruncated values.
  2. Compare the agent's KEY with the public key registered on the hub for this agent ID.
  3. Verify the token is well-formed and not expired; re-fetch a fresh token from the hub.
  4. Confirm both sides use the same signature algorithm and encoding; update agent or hub versions if they diverge.

Example fix

// before
HUB_URL=wss://hub.prod
KEY="Kf2..."   # key from staging
TOKEN="eyJ..."  # issued by prod hub
// after
HUB_URL=wss://hub.prod
KEY="<prod key matching this TOKEN>"
TOKEN="eyJ..."
Defensive patterns

Strategy: try-catch

Validate before calling

// before connecting, sanity-check the key material
key, err := base64.StdEncoding.DecodeString(strings.TrimSpace(keyEnv))
if err != nil {
	return fmt.Errorf("KEY is not valid base64: %w", err)
}
if len(key) != expectedKeyLen {
	return fmt.Errorf("KEY length %d, expected %d — likely truncated", len(key), expectedKeyLen)
}

Try / catch

err = verifySignature(client, challenge)
if err != nil {
	if strings.Contains(err.Error(), "invalid signature") {
		log.Error("auth failed: KEY does not match TOKEN/hub expectation; refetch credentials")
		// do NOT blind-retry with the same key; rotate credentials first
		return errAuthRetryableAfterRefresh
	}
	return err
}

Prevention

When it happens

Trigger: handleAuthChallenge receives a challenge; the client signs the token with its private key but verification against pubKey fails — KEY is wrong, mismatched with TOKEN, the token is malformed/expired for signing purposes, or the signature algorithm/encoding differs from what the hub expects.

Common situations: Rotating TOKEN without updating KEY (or vice versa) on the hub; copy-paste truncating the base64 KEY; hub and agent using different key algorithms (ed25519 vs ecdsa); agent pointed at the wrong hub environment (staging key vs prod hub).

Related errors


AI-assisted analysis of henrygd/beszel@b38fb7dafa (2026-08-31). Data as JSON: /api/errors/87ee0bdb42ae87b2. Report an issue: GitHub.