hello there :slightly_smiling_face: I'm developin...
# developer
c
hello there 🙂 I'm developing a cluster driver for exoscale.com and I have a working POC, and I have a JS components imported with pretty much all the cloud provider zone, instance-type...etc hard coded, but now I'm working on getting it dynamically, to be more reliable, I'm using the proxy and whitlist my hostname but I have a 401 from the proxy Here is the full implem: https://gist.github.com/pierre-emmanuelJ/b864f0ccffc1272793566f2699026b37
Copy code
apiRequest(endpoint, method = 'GET', params = {}, body = '', apikey, secret) {
    const baseUrl = `${get(this, 'app.proxyEndpoint')}/${this.exoscaleApi}`;
    const url = `${baseUrl}/${endpoint}`;
    const expires = Math.floor(Date.now() / 1000) + 600; // Expiration time (10 minutes from now)

    // Sort query params alphabetically
    const sortedParams = Object.keys(params).sort();
    const queryString = new URLSearchParams(params).toString();
    const queryValues = sortedParams.map((key) => params[key]).join('');

    // Ensure body is properly formatted
    const requestBody = body ? JSON.stringify(body) : '';


    const apiPath = `/v2/${endpoint}`;

    // Construct the message to sign (avoiding extra newlines)
    const messageParts = [
      `${method} ${apiPath}`,  // Correct request path (excluding proxy)
      requestBody || '',        // Ensure empty string instead of null/undefined
      queryValues || '',        // Ensure empty string if no query params
      '',                       // No signed headers for now
      expires.toString(),       // Expiration timestamp
    ];
    const message = messageParts.join('\n');

    console.log("Message to sign:", JSON.stringify(message, null, 2));

    // Convert secret key to Uint8Array
    const secretKey = new TextEncoder().encode(secret);
    const messageData = new TextEncoder().encode(message);

    console.log("secret and messagedata encoded:", secretKey, messageData);

    // Compute HMAC using Web Crypto API
    return crypto.subtle.importKey(
      "raw",
      secretKey,
      { name: "HMAC", hash: { name: "SHA-256" } },
      false,
      ["sign"]
    ).then((cryptoKey) => {
      return crypto.subtle.sign("HMAC", cryptoKey, messageData);
    }).then((signatureBuffer) => {
      // Convert ArrayBuffer to Base64
      const signatureArray = new Uint8Array(signatureBuffer);
      const signature = btoa(String.fromCharCode(...signatureArray));

      // Build the Authorization header
      let authorizationHeader = `EXO2-HMAC-SHA256 credential=${apikey},expires=${expires},signature=${signature}`;
      if (sortedParams.length > 0) {
        authorizationHeader = `EXO2-HMAC-SHA256 credential=${apikey},signed-query-args=${sortedParams.join(';')},expires=${expires},signature=${signature}`;
      }

      console.log("Final Authorization Header:", authorizationHeader);

      // Construct request options
      const options = {
        url: queryString ? `${url}?${queryString}` : url, // Include query if exists
        method,
        dataType: 'json',
        headers: {
          Accept: 'application/json',
          'Content-Type': 'application/json',
          Authorization: authorizationHeader,
        },
        data: method === 'POST' ? requestBody : undefined,
      };

      console.log("Final AJAX Request:", JSON.stringify(options, null, 2));
      console.log(this.app, this.session, this.intl);

      return ajaxPromise(options, true);
    }).then((response) => {
      return response;
    }).catch((err) => {
      console.error('API Request Error:', err);
      throw err;
    });
  }
Did I miss something in my header or so? I still got
{"type":"error","status":"401","message":"Unauthorized 401: must authenticate"}