"msg": "sign invalid", when trying to generate token for tuya cloud development

App development related product technical discussions, including OEM App, App SDK, device control interface development, mini program development and other topics.


Post Reply
GoGyde23
Posts: 3

I've set up a cloud project in Tuya, and I'm trying to write Java code in Android Studio to turn on a Wi-Fi socket. However, I'm encountering an issue.

Here's my code:

Code: Select all

public class TuyaApiHelper {

    private static final String TAG = "TuyaHelper";
    private static final String ACCESS_ID = "Access id from cloud project overview section";
    private static final String ACCESS_SECRET = "Access secret from cloud project overview section";
    private static final String DEVICE_ID = "Device id";  // ← Replace this
    private static final String BASE_URL = "https://openapi.tuyacn.com";

    private static final OkHttpClient client = new OkHttpClient();
    private static final ExecutorService executor = Executors.newSingleThreadExecutor();

    public interface Callback {

        void onSuccess(String result);
        void onFailure(String error);
    }

    public static void switchDevice(final boolean turnOn, final Callback callback) {
        getAccessToken(new Callback() {
            @Override
            public void onSuccess(String token) {
                sendCommand(token, turnOn, callback);
            }

            @Override
            public void onFailure(String error) {
                callback.onFailure("Token error: " + error);
            }
        });
    }

    private static void getAccessToken(final Callback callback) {
        long timestamp = System.currentTimeMillis();
        String stringToSign = ACCESS_ID + timestamp;
        String sign = hmacSHA256(stringToSign, ACCESS_SECRET).toUpperCase();

        String url = BASE_URL + "/v1.0/token";

        Request request = new Request.Builder()
                .url(url)
                .get()
                .addHeader("client_id", ACCESS_ID)
                .addHeader("sign", sign)
                .addHeader("t", String.valueOf(timestamp))
                .addHeader("sign_method", "HMAC-SHA256")
                .build();

        client.newCall(request).enqueue(new okhttp3.Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                callback.onFailure(e.getMessage());
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                String json = response.body().string();
                try {
                    JSONObject obj = new JSONObject(json);
                    String token = obj.getJSONObject("result").getString("access_token");
                    callback.onSuccess(token);
                } catch (Exception e) {
                    callback.onFailure("Parsing error: " + e.getMessage() + " \n Response: " + json);
                }
            }
        });
    }

    private static void sendCommand(String token, boolean turnOn, Callback callback) {
        String endpoint = "/v1.0/iot-03/devices/" + DEVICE_ID + "/commands";
        String url = BASE_URL + endpoint;

        String value = turnOn ? "true" : "false";
        String json = "{\n" +
                "  \"commands\": [\n" +
                "    {\n" +
                "      \"code\": \"switch_1\",\n" +
                "      \"value\": " + value + "\n" +
                "    }\n" +
                "  ]\n" +
                "}";

        RequestBody body = RequestBody.create(json, MediaType.get("application/json"));

        long timestamp = System.currentTimeMillis();
        String signStr = ACCESS_ID + token + timestamp;
        String sign = hmacSHA256(signStr, ACCESS_SECRET).toUpperCase();

        Request request = new Request.Builder()
                .url(url)
                .post(body)
                .addHeader("client_id", ACCESS_ID)
                .addHeader("access_token", token)
                .addHeader("t", String.valueOf(timestamp))
                .addHeader("sign_method", "HMAC-SHA256")
                .addHeader("sign", sign)
                .addHeader("Content-Type", "application/json")
                .build();

        client.newCall(request).enqueue(new okhttp3.Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                callback.onFailure(e.getMessage());
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                callback.onSuccess(response.body().string());
            }
        });
    }

    private static String hmacSHA256(String data, String key) {
        try {
            Mac sha256_HMAC = Mac.getInstance("HmacSHA256");
            SecretKeySpec secret_key = new SecretKeySpec(key.getBytes("UTF-8"), "HmacSHA256");
            sha256_HMAC.init(secret_key);
            byte[] hash = sha256_HMAC.doFinal(data.getBytes("UTF-8"));

            StringBuilder sb = new StringBuilder();
            for (byte b : hash) {
                sb.append(String.format("%02x", b));
            }
            return sb.toString();
        } catch (Exception e) {
            return "";
        }
    }
}

Code: Select all

    public static String sha256_HMAC(String clientId, String clientSecret, String timestamp) throws NoSuchAlgorithmException, InvalidKeyException {
        String message = clientId + timestamp;

        Mac sha256_HMAC = Mac.getInstance("HmacSHA256");
        SecretKeySpec secretKey = new SecretKeySpec(clientSecret.getBytes(StandardCharsets.UTF_8), "HmacSHA256");
        sha256_HMAC.init(secretKey);

        byte[] hash = sha256_HMAC.doFinal(message.getBytes(StandardCharsets.UTF_8));

        // Convert bytes to hex
        StringBuilder hexString = new StringBuilder();
        for (byte b : hash) {
            String hex = Integer.toHexString(0xff & b);
            if (hex.length() == 1) hexString.append('0');
            hexString.append(hex);
        }

        return hexString.toString().toUpperCase(); // Tuya requires UPPERCASE hex
    }

    private static String bytesToHex(byte[] bytes) {
        StringBuilder sb = new StringBuilder();
        for (byte b : bytes)
            sb.append(String.format("%02x", b));
        return sb.toString();
    }

I am getting "code": 1004, "msg": "sign invalid" response. Am I missing any thing in the creating the sign string. Any help is appreciated.

bohan
Posts: 7

Re: "msg": "sign invalid", when trying to generate token for tuya cloud development

We do not recommend connecting to the cloud development interface within an Android app. This is because if you do so, you will need to write the cloud project's secret key in the app code. So why would you want to do this? We also have an SDK for the app that can be used to perform operations such as turning on or off certain functions.

GoGyde23
Posts: 3

Re: "msg": "sign invalid", when trying to generate token for tuya cloud development

Thanks for the reply. This is project is for a quick MVP, So just wanted to get something up and running. Can you please give me more information on the SDK you are talking about. A reference to a document on how I can implement would be helpful.

GoGyde23
Posts: 3

Re: "msg": "sign invalid", when trying to generate token for tuya cloud development

I followed this document and I lost myself . I am creating an app for electric vehicle charging. The users will login to my app using Firebase Phone Auth and click on a start button. This should start charging their vehicle and when they click on stop button it should stop.

I have downloaded smart life app and added my smart sockets there. I have linked these devices to my tuya cloud project.

Can somebody provide me the steps to do to achieve this ? Thanks

bohan
Posts: 7

Re: "msg": "sign invalid", when trying to generate token for tuya cloud development

Sorry, we currently do not support the method of directly pulling Tuya devices into your own app.

However, if you have your own cloud service, you can integrate it with the Tuya Cloud Service to manage Tuya devices. This is the approach you initially asked about.

Then, you can have your app request your cloud service to query Tuya device information or control Tuya devices.

Post Reply