OpenWonderLabs / SwitchBotAPI

SwitchBot Open API Documents
868 stars 71 forks source link

Possibility to authenticate without calculating the sign every time? #339

Open taulfsime opened 2 months ago

taulfsime commented 2 months ago

Current Situation

Hello, I'm writing Javascript code that will run on an esp32-based device. I don't have a lib to calculate the sign every time I want to send a request. Is it possible to calculate it once and reuse it for several requests?

Logs

If I use an already generated sign (together with the nonce, t, Authorization key), I get `statusCode: 401
{"message":"Unauthorized"}` on every request, if I edit the script to calculate the sign just before sending it, it works.

Configuration

`auth` - contains already generated sign, Authorization key, nonce, and t (same as when the sign is generated)

const options = {
  hostname: 'api.switch-bot.com',
  port: 443,
  path: `/v1.1/devices/`,
  method: 'GET',
  headers: {
    ...auth,
    'Content-Type': 'application/json',
    'Content-Length': 0,
  },
};

const req = https.request(options, res => {
  console.log(`statusCode: ${res.statusCode}`);
  res.on('data', d => {
      process.stdout.write(d);
  });
});

req.on('error', error => {
  console.error(error);
});

Environment

Additional Context

No response

ThatProgrammerr commented 2 months ago

You could proxy the request via another server, if needed. Although, I can see why you'd want to keep everything on device. From my understanding, this is very much a required part of the headers sent with your request. I use python, and use this function to auth.

Edit: Since the sign contains timestamp of the request, you'd need to generate it everytime, as otherwise the switchbot API, likely within a margin of a few seconds, or a minute will invalidate your request. I doubt they'll change this.


def prepare_header():
    nonce = str(uuid.uuid4())
    timestamp = str(int(round(time.time() * 1000)))
    string_to_sign = f"{TOKEN}{timestamp}{nonce}"
    bytes_to_sign = bytes(string_to_sign, "utf-8")
    secret_bytes = bytes(SECRET, "utf-8")
    signature = hmac.new(
        secret_bytes, msg=bytes_to_sign, digestmod=hashlib.sha256
    ).digest()
    encoded_signature = base64.b64encode(signature).decode("utf-8")
    apiHeader = {
        "Authorization": TOKEN,
        "Content-Type": "application/json",
        "charset": "utf-8",
        "t": timestamp,
        "sign": encoded_signature,
        "nonce": nonce,
    }
    return apiHeader