POST ListCorpora endpoint gives 401 error

the API endpoint POST /v1/list-corpora returns a 401.
I have tried this with both an API key and OAUTH key and get the same “JWT Token failed to authenticate” message. I have used the API key successfully with the query gRPC so I know it is correct.

Am I missing something on my end or does my account need special permission to get this endpoint?

api_key = "my-api-key"

headers = {
  "Content-Typ": "application/json",
  "Accept": "application/json",
  "Authorization": f"{api_key}",
  "customer-id": f"{VECTARA_CUSTOMER_ID}"
}
base_url = "https://api.vectara.io/"
corpora_url = "v1/list-corpora"

payload = json.dumps({
  "filter": "string",
  "numResults": 0,
  "pageKey": "string"
})

response = requests.request("POST", f"{base_url}{corpora_url}", headers=headers, data=payload)

response.text
'{"code":16,"message":"JWT Token failed to authenticate.","details":[]}'

Hey there @that1guy15 , and welcome!

Just quickly (this is unrelated to the error you’re seeing) but Content-Typ should read Content-Type. Also, you’ll want to double check that you have a valid string for filter and pageKey in the payload object (or just drop these; they can be empty) and presumably you want some non-zero number for numResults as well.

In terms of authentication/authorization, as you note there are 2 types that Vectara supports: API key and OAuth. We haven’t enabled API key authentication for administrative actions (such as listing corpora), so for this particular API, you’ll need to use OAuth. When using OAuth tokens, you’ll need Authorization: Bearer <token>. The token you use there/that the OAuth service returns is a JWT token which should start with the characters ey if you look at it. e.g. your Authorization header should look something like Authorization: Bearer eyJ....

(If/when you use API keys for other APIs like adding content to a corpus or searching, you’ll want to drop the Authorization header entirely and instead have an x-api-key header.)

One other point is that you have to make sure that the identity you are authenticating as (the App Client or the API Key) needs to have proper permissions.

  • For list-corpora to work, the App Client should have at least CORPUS_ADMIN/COR role.

  • For query to work, the App Client should have at least QRY role on that corpus, and the Api Key should have that corpus added to it when you create the key.

Got it working. It was a combination of not having the right formate for the Authorization header and missing the right permissions on the API key like @justin mentioned below.

Thanks for the quick response!

1 Like

Sorry to drag this one back up but I am still having issues using query (GRPC) with an OAUTH key.

I have validated the Corpus has both admin and query roles assigned to this app-key and the app-key has both Admin and Corpus Admin roles assigned.

My code matches the getting-started python GRPC code with the following

        try:
            query_stub = services_pb2_grpc.QueryServiceStub(
                grpc.secure_channel("serving.vectara.io",
                                    grpc.ssl_channel_credentials()))
            packed_customer_id = struct.pack(">q", int(self.customer_id))
            response = query_stub.Query(batch_request,
                                        **metadata=[("customer-id-bin", packed_customer_id),**
**                                                  ("x-api-key", "ey-oauth-key-from-session")])**
            print(f"Query succeeded with response: {response}")
            return None, True

ey-oauth-key-from-session is the key returned from POST /oauth2/token in the ‘access_token’ property starting with ‘ey’ as pointed out above. This logic works just fine if I use ("Authorization": "user-api-key")

The returned error I get is:

<_InactiveRpcError of RPC that terminated with:
	status = StatusCode.UNAUTHENTICATED
	details = "API Key is invalid."
	debug_error_string = "{"created":"@1680040543.856658000","description":"Error received from peer ipv4:52.25.172.92:443","file":"src/core/lib/surface/call.cc","file_line":967,"grpc_message":"API Key is invalid.","grpc_status":16}"
>

Hi,

Vectara supports two types of authentication.

  1. OAuth (For query, indexing and admin actions)
  2. Api Key (For query and indexing only)

In your example code, you are calling a query API and the authentication mechanism you are using is API Key as indicated by this line: ("x-api-key", "ey-oauth-key-from-session")])**
However, you are passing it an OAuth key instead of an API Key.
An API Key starts with zqt_ or zwt_

You can get your API key from Vectara console by logging in and going to Api Keys

makes sense. What do I use instead of x-api-key when I want to pass it an OAuth key?

In that case, you pass:

Authorization: Bearer {token}

You can see the example code here (getting-started/rest_query.py at b604692dd5ad3b653a86316ead29c0cf4575d1c2 · vectara/getting-started · GitHub)

The gPRC metadata does not like the “Authorization” header.

response = query_stub.Query(batch_request,
                              metadata=[("customer-id-bin", packed_customer_id),
                                        ("Authorization", self.access_token)])

Here are the gPRC error logs I get back.

E0329 13:33:32.110820000 8606115328 call.cc:843]                       validate_metadata: {"created":"@1680114812.110769000","description":"Illegal header key","file":"src/core/lib/surface/validate_metadata.cc","file_line":52,"offset":0,"raw_bytes":"41 75 74 68 6f 72 69 7a 61 74 69 6f 6e 'Authorization'\u0000"}
Traceback (most recent call last):
 ---snip python trace ---

  File "src/python/grpcio/grpc/_cython/_cygrpc/channel.pyx.pxi", line 496, in grpc._cython.cygrpc.Channel.segregated_call
  File "src/python/grpcio/grpc/_cython/_cygrpc/channel.pyx.pxi", line 366, in grpc._cython.cygrpc._segregated_call
  File "src/python/grpcio/grpc/_cython/_cygrpc/channel.pyx.pxi", line 360, in grpc._cython.cygrpc._segregated_call
  File "src/python/grpcio/grpc/_cython/_cygrpc/channel.pyx.pxi", line 218, in grpc._cython.cygrpc._call
  File "src/python/grpcio/grpc/_cython/_cygrpc/channel.pyx.pxi", line 253, in grpc._cython.cygrpc._call
  File "src/python/grpcio/grpc/_cython/_cygrpc/channel.pyx.pxi", line 61, in grpc._cython.cygrpc._raise_call_error
ValueError: metadata was invalid: [('customer-id-bin', b'\x00\x00\x00\x00/\xe6\x99t'), ('Authorization', 'Bearer ey-oauth-key-from-session)]

Could it be the proto files Im using are out of date?
I pulled these from the github proto repo back on march 9th and I see new versions have been uploaded.

I think I misread your original question a little bit.
For gRPC, you don’t need to pass Authorization as part of metadata.
You need to pass access_token as credentials

So your code will look like:

query_stub = services_pb2_grpc.QueryServiceStub(
                grpc.secure_channel("serving.vectara.io",
                                    grpc.ssl_channel_credentials()))
packed_customer_id = struct.pack(">q", int(self.customer_id))
response = query_stub.Query(batch_request,
                            credentials=grpc.access_token_call_credentials(self.access_token),
                            metadata=[("customer-id-bin", packed_customer_id)])
print(f"Query succeeded with response: {response}")
return None, True

Look here for an example on how to do this: getting-started/grpc_basic_operations.py at b604692dd5ad3b653a86316ead29c0cf4575d1c2 · vectara/getting-started · GitHub

Thats it. works perfect.
Thank you!

1 Like