IOT API NodeJS Token Auth 401 Problem

Hello first of all I appreciate any help! :grinning:

[Arduino Cloud API 401 Issue - Pastebin.com]

What is the project ? :

I am building a NodeJS API to interface with other API's. I am currently working on an endpoint to call Arduinos Cloud IOT API endpoints. I followed the documentation for JavaScript.

What is the problem ? :

I was able to use my ClientID and Secret ( stored as env variables ) from Arduino's intergrations section to obtain a valid response. I got a 200 status and received a token. I extracted the token as described in the documentation from Arduino and stored it in the client instance as described. However, when calling the API via the ThingsV2Api or DevicesV2Api I am getting an error. The error is a 401 that still says my application is "unauthorized" even though I'm almost 100% sure I have a valid token and headers set.

Where is the code?:

I will be posting the code on pastebin as well as on here. I will also be posting all output I have gotten that does not expose my secret. I have also tired not using the API and making the calls myself via Fetch() I got the same 401 response.

    app.get('/v1/Arduino', (req, res) => {

    async function getToken() {
        let options = {
            method: 'POST',
            body: 'grant_type=client_credentials&client_id=' + process.env.ARDUINO_CLIENT_ID + '&client_secret=' + process.env.ARDUINO_SECRET_TOKEN + '&audience=' + 'https://api2.arduino.cc/iot',
            headers: { 'content-type': 'application/x-www-form-urlencoded' },
        };

        try {
            const response = await fetch(ArduinoUrl, options);

            //console.log("\n Response from POST : ");
            //console.log( response);
            //console.log("\n Response Status: " + response.status);

            if (!response.ok) {
                const message = `An error has occured: ${response.status}`;
                throw new Error(message);
            }
            else {
                //response.json() is a method on the Response object that lets you extract a JSON object from the response
                const tokenPackage = await response.json();
                const token = (tokenPackage['access_token']);

                //console.log("\n Package: " + tokenPackage);
                //console.log(tokenPackage);
                //console.log("\n Token is : " + token);

                return token;
            }
        }
        catch (error) {
            console.error("Failed getting an access token: " + error);
        }
    }

    async function useToken() {
        try {
            const client = IotApi.ApiClient.instance;
            const oauth2 = client.authentications['oauth2'];

            oauth2.access_token = await getToken();
            //const token = await getToken();
            
            //console.log("\n After waiting for token in useToken() : " , oauth2.access_token);

            /* let options2 = {
                method: 'GET',
                headers: {
                    'Authorization': `Bearer ${token}`,
                    'Content-Type': 'application/json'
                }
            };

            try {

                const IotTestUrl = "https://api2.arduino.cc/iot/v2/things?across_user_ids=true";
                 url:              'https://api2.arduino.cc/iot/v2/devices',

                const response = await fetch(IotTestUrl, options2);

                console.log("\n Response from GET : " + response);
                console.log("\n Response Status: " + response.status);

                if (!response.ok) {
                    const message = `An error has occured: ${response.status}`;
                    console.log(response);
                    
                    throw new Error(message);
                }
                else {
                    //response.json() is a method on the Response object that lets you extract a JSON object from the response
                    const data = await response.json();

                    console.log("\n Data: " + data);
                    
                    return data;
                }
            }
            catch (error) {
                console.error("Failed getting an access token: " + error);
               
            }*/

             let websiteControllerApi = new IotApi.ThingsV2Api(client);

             //console.log("Client object: ", client);

             //console.log("Webcontroller object: ", websiteControllerApi.apiClient.authentications);
 
             websiteControllerApi.thingsV2List(true).then( (things) =>{
                
                //console.log("Webcontroller object: ", websiteControllerApi.apiClient.authentications);
                console.log( "\n Returning things : " , things);
                
             },(error)=>{
                //console.log("Error Webcontroller object: ", websiteControllerApi.apiClient.authentications);
                console.log( "\n Error returning things : " , error);
                
             });

        } catch (error) {
            console.log("oauth error:" , error);
        }
    }

    /* useToken().catch(error => {
        console.log(" useToken() error" , error);
    }); */

    useToken();

    /* useToken().then(data => {
        //res.status(200).send(data);
    }) */ })

ERROR MESSAGE

Error message from GET

UPDATE !!!

So I got the endpoint to work when calling it via my own fetch() request. It turns out it wasn't working for that specific URL I was trying to call. I got it to work with this updated code. However I'm still stumped as to why the API instance won't work.

try {
                const IotTestUrl = "https://api2.arduino.cc/iot/v2/devices";
                //url:              'https://api2.arduino.cc/iot/v2/devices',

                const response = await fetch(IotTestUrl, options2);

                console.log("\n Response from GET : " , response);
                console.log("\n Response Status: " + response.status);

                if (!response.ok) {
                    const message = `\n An error has occured: ${response.status}`;
                    //console.log(response);
                    
                    throw new Error(message);
                }
                else {
                    //response.json() is a method on the Response object that lets you extract a JSON object from the response
                    const data = await response.json();

                    console.log("\n Data: ", data);
                    //return data;
                }
            }
            catch (error) {
                console.error("\n Failed GET request: ", error);
            }

I went through similar pain getting the Python API to work.

I don't know where you are getting your example code from, but I found the Python examples in the API reference to be incorrect. I think they may be for V1 rather than V2, but I'm not certain.

Anyway, when I used the "smoke test" example in the github repository as a model and it all sprang to life. I used the Python version of the example, but I noticed that there is a node js version of it too, here. It might be worth running it without modification first to see if it's a goer, then extrapolate to do what you want.

1 Like

Hey I appreciate taking your time to reply. I noticed that too! The documentation seems to be a bit outdated and the repo hasn't been updated in 6 months I believe. I think the example from the JS version is also not working. I have not been able to get their API to work via the methods they show. However, I was able to work around it just using standard HTTP calls ! So I can now communicate with my board :grinning: . However the original problem is still a mystery and sadly I don't have time to try and debug ( especially after already debugging for 3+ hrs ).

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.