4

I followed the instructions of generating a Python gPRC client from here but struggle to provide a token to the request

Insecure Channel does not work

auth_creds = grpc.access_token_call_credentials(TOKEN)
channel = grpc.insecure_channel('localhost:10000', auth_creds)

>> TypeError: 'CallCredentials' object is not iterable

Secure Channel does not work either

auth_creds = grpc.access_token_call_credentials(TOKEN)
channel = grpc.secure_channel('localhost:10000', auth_creds)

>> TypeError: Argument 'channel_credentials' has incorrect type (expected grpc._cython.cygrpc.ChannelCredentials, got grpc._cython.cygrpc.MetadataPluginCallCredentials)

According to python gRPC documentation

A CallCredentials has to be used with secure Channel, otherwise the metadata will not be transmitted to the server.

However, how do I create a secure channel, since methods which create these ChannelCredentials correspond to ssl or similar, no?

In addition to that, it seems to be possible to simply parse the tuple {'Authorization':'Bearer <TOKEN>'} as meta data like here. However, I noticed - as in the comment raised - upper case characters are not allowed.

with_call Method with credentials does not also not work

auth_creds = grpc.access_token_call_credentials(TOKEN)
channel = grpc.secure_channel('localhost:10000', auth_creds)
stub = foo_bar_pb2_grpc.ServiceStub(channel)
response = stub.Get.with_call(message_pb2.Message(), credentials=auth_creds)

>> TypeError: Argument 'channel_credentials' has incorrect type (expected grpc._cython.cygrpc.ChannelCredentials, got grpc._cython.cygrpc.MetadataPluginCallCredentials)

with_call Method with metadata does not also not work

metadata = 'Authorization', 'Bearer <TOKEN>'
channel = grpc.insecure_channel('localhost:10000')
stub = foo_bar_pb2_grpc.ServiceStub(channel)
response = stub.Get.with_call(message_pb2.Message(), metadata=metadata))

>> ValueError: too many values to unpack (expected 2)

Summarized: How do I authenticate my client with an access token?

patientCoder
  • 71
  • 1
  • 6

2 Answers2

3

I had a similar issue trying to send a custom header in a secure channel.

In my case, the problem came from using:

metadata = (('my-header-key', 'my-header-value'))

Instead of:

metadata = [('my-header-key', 'my-header-value')]

My code:

credentials = grpc.ssl_channel_credentials()
with grpc.secure_channel("<HOST>:<PORT>", credentials) as channel:
    rpc_service = my_pb2_grpc.MyServiceStub(channel)
    request = my_pb2.MyData(my_data='data')
    metadata = [('my-header-key', 'my-header-value')]
    response = rpc_service.MyMethod(request=request, metadata=metadata)
josmaf
  • 148
  • 1
  • 9
  • The code snippet was helpful, but your problem was mis-diagnosed. You can use a tuple for metadata (not a list), but a 1-element tuple must have a trailing `,`, e.g., `metadata = (('my-header-key', 'my-header-value'),)`. Otherwise, the parentheses are parsed as simply a grouping operation, not a tuple creation. – kris Mar 01 '23 at 16:58
2

As stated by the same docstring:

A CallCredentials may be composed with ChannelCredentials to always assert identity for every call over that Channel.

and a ChannelCredentials object is what your type error from grpc.secure_channel was screaming for. To do that composition, you need to encrypt the channel with SSL/TLS. Here is a client example with a token:

with open("server.crt", 'rb') as fd:
    root_c = fd.read()
scc = grpc.ssl_channel_credentials(root_certificates=root_c)

tok = grpc.access_token_call_credentials("super-secret-token")
ccc = grpc.composite_channel_credentials(scc, tok)

with grpc.secure_channel("localhost:8080", ccc) as channel:
    #... create stub and do the call
    pass

For some more complete examples with SSL checkout this https://github.com/joekottke/python-grpc-ssl or this https://www.sandtable.com/using-ssl-with-grpc-in-python/. The official doc might also be helpful to look at.

A token is something you don't want anyone to sniff and I guess that's why you are required to use it in a secure_channel by the gRPC library.

Smiths
  • 23
  • 1
  • 6