lookininward
lookininward

Reputation: 671

Why can't Clarifai validate model output request with API key generated in the Clarifai Portal or with the Personal Access token?

Update

I'm able to get my original code, and the suggestions as well working when running it in isolation. However, what I need to do is call it from within a Firebase onRequest or onCall function. When this code gets wrapped by these, the malformed headers and request for authorization are still an issue. We use many other APIs this way so it's puzzling why the Clarifiai API is having these issues. Any suggestions on using it with Firebase?

Original

New to Clarifai and having some authentication issues while attempting to retrieve model outputs from the Food Model.

I've tried two different keys:

In both cases I encounter an Empty or malformed authorization header response.

{
   "status":{
      "code":11102,
      "description":"Invalid request",
      "details":"Empty or malformed authorization header. Please provide an API key or session token.",
      "req_id":"xyzreasdfasdfasdfasdfasf"
   },
   "outputs":[
      
   ]
}

I've following the following articles to piece together this code. This is running in a Node 10 environment.

  const { ClarifaiStub } = require('clarifai-nodejs-grpc');
  const grpc = require('@grpc/grpc-js');
  const stub = ClarifaiStub.json();
  const metadata = new grpc.Metadata();
  metadata.set("authorization", "Key xyzKey");

  return new Promise((resolve, reject) => {
    stub.PostModelOutputs(
      {
        model_id: 'bd367be194cf45149e75f01d59f77ba7',
        inputs: [{ data: { image: { url: 'https://samples.clarifai.com/metro-north.jpg' } } }],
      },
      metadata,
      (err, response) => {
        if (err) {
          return reject(`ERROR: ${err}`);
        }

        resolve(JSON.stringify(response));
      }
    );
  });
}

Upvotes: 0

Views: 528

Answers (3)

Rok Povsic
Rok Povsic

Reputation: 4935

Update: There was an issue in versions prior to 7.0.2 where, if you had another library using @grpc/grpc-js with a different version, the grpc.Metadata object wasn't necessarily constructed from the library version that clarifai-grpc-nodejs was using.

To fix the issue, update the clarifai-grpc-nodejs library, and require the grpc object like this:

const {ClarifaiStub, grpc} = require("clarifai-nodejs-grpc");

Previously, the grpc object was imported directly from @grpc/grpc-js, which was the source of the problem.


There are two ways of authenticating to the Clarifai API:

  • with an API key, which is application-specific, meaning that an API key is attached to an application and can only do operations inside that application,
  • with a Personal Access Token (PAT), which is user-specific, which means you can assess / manipulate / do operations on all the applications the user owns / has access to (and also create/update/delete applications themselves).

When using a PAT, you have to specify, in your request data, which application you are targeting. With an API key this is not needed.

I've tested your example (using Node 12, though it should work in 10 as well) with a valid API key and it works fina (after putting it into an async function). Here's a full runnable example (replace YOUR_API_KEY with your valid API key).

function predict() {
  const { ClarifaiStub } = require('clarifai-nodejs-grpc');
  const grpc = require('@grpc/grpc-js');
  const stub = ClarifaiStub.json();
  const metadata = new grpc.Metadata();
  metadata.set("authorization", "Key YOUR_API_KEY");

  return new Promise((resolve, reject) => {
    stub.PostModelOutputs(
      {   
        model_id: 'bd367be194cf45149e75f01d59f77ba7',
        inputs: [{ data: { image: { url: 'https://samples.clarifai.com/metro-north.jpg' } } }], 
      },  
      metadata,
      (err, response) => {
        if (err) {
          return reject(`ERROR: ${err}`);
        }

        resolve(JSON.stringify(response));
      }   
    );  
  }); 
}

async function main() {
    const response = await predict();
    console.log(response);
}

main();

If you want to use a PAT in the above example, two things must change. Firstly, replace the API key with a PAT:

...
metadata.set("authorization", "Key YOUR_PAT");
...

To the method request object, add the application ID.

...
    stub.PostModelOutputs(
      {
         user_app_id: {
           user_id: "me",  // The literal "me" resolves to your user ID.
           app_id: "YOUR_APPLICATION_ID"
         },
        model_id: 'bd367be194cf45149e75f01d59f77ba7',
        inputs: [{ data: { image: { url: 'https://samples.clarifai.com/metro-north.jpg' } } }], 
      },
...

Upvotes: 2

syntheticgio
syntheticgio

Reputation: 608

EDIT: So looks like Firebase doesn't support custom headers. This is likely impacting the 'Authorization' header. At least this is my best guess. See the comments in the following ticket.

Firebase hosting custom headers not working


The following code works for me:

{
  const { ClarifaiStub } = require('clarifai-nodejs-grpc');
  const grpc = require('@grpc/grpc-js');
  const stub = ClarifaiStub.json();
  const metadata = new grpc.Metadata();
  metadata.set("authorization", "Key {APP API KEY}");

  return new Promise((resolve, reject) => {
    stub.PostModelOutputs(
      {
        model_id: 'bd367be194cf45149e75f01d59f77ba7',
        inputs: [{ data: { image: { url: 'https://samples.clarifai.com/metro-north.jpg' } } }],
      },
      metadata,
      (err, response) => {
        if (err) {
          return reject(`ERROR: ${err}`);
        }
        console.log(JSON.stringify(response));
        resolve(JSON.stringify(response));
      }
    );
  });
}

There was a missing { although I'm not sure if that is what is reflected in the actual code you are running. I'm using in this case an APP API Key (when you create an App, there will be an API Key on the Application Details page.

It sounds like you might be using a Personal Access Token instead, which can be used like this:

{  
  const { ClarifaiStub } = require('clarifai-nodejs-grpc');
  const grpc = require('@grpc/grpc-js');
  const stub = ClarifaiStub.json();
  const metadata = new grpc.Metadata();
  metadata.set("authorization", "Key {Personal Access Token}"); // Sounds like you've made the personal access token correctly - go into settings, then authentication, then create one.  Make sure it has proper permissions (I believe all by default).

  return new Promise((resolve, reject) => {
    stub.PostModelOutputs(
      {
        user_app_id: {
          user_id: "{USER ID}",  // I used my actual ID, I did not put 'me'.  You can find this under your profile.
          app_id: "{APP NAME}" // This is the app ID found in the upper left corner of the app after it is created - not the API Key.  This is generally what you named the app when you created it.
        },
        model_id: 'bd367be194cf45149e75f01d59f77ba7',
        inputs: [{ data: { image: { url: 'https://samples.clarifai.com/metro-north.jpg' } } }],
      },
      metadata,
      (err, response) => {
        if (err) {
          return reject(`ERROR: ${err}`);
        }
        console.log(JSON.stringify(response));
        resolve(JSON.stringify(response));
      }
    );
  });
}

Make sure to fill out the: {Personal Access Token}, {USER ID} and {APP NAME}. I used my actual user id (found in the profile), and the app name is not the API Key for the app, but the name in the upper left corner when you're on the Application details page. This call worked for me.

Upvotes: 0

Jeremy Faret
Jeremy Faret

Reputation: 326

Make sure that you have respected the format to pass the key in your code as such:

const metadata = new grpc.Metadata();
metadata.set("authorization", "Key {YOUR_CLARIFAI_API_KEY}");

Make sure that "Key" is present.

Let me know.

Upvotes: 0

Related Questions