How to add Channel Credentials?
maitham opened this issue · 3 comments
I currently have the following code:
composite_credentials = grpc.composite_channel_credentials(
ssl_credentials, google_auth_credentials
)
Channel(host, port, ssl=composite_credentials, loop=loop)
This doesn't work as this returns a composite ChannelCredentials object as per https://www.grpc.io/docs/guides/auth/ . Is this currently supported? Or should I try to get the headers required for authenticating requests to google?
grpclib currently has only basic building blocks to perform authentication. Vendor-specific auth mechanisms (Google) aren't supported because I'm not using these services and I don't know the best way to implement this functionality.
If you want to use certificate-based auth – use ssl option when create Channel:
Channel(..., ssl=custom_ssl_context)
This ssl
option can be True
or instance of the ssl.SSLContext
class. So it is not possible to pass your composite_credentials
to this option. I have an example of how to perform mutual TLS auth: examples/mtls/client.py, maybe this will help. And probably I have to add more documentation about TLS authentication.
If you want to use token-based auth – make sure you're using secure connection (Channel(..., ssl=True)
), and send auth token with request metadata. There is two ways to send auth token in request metadata:
- explicitly in every request:
stub.Method(..., metadata={token})
- implicitly using events: https://grpclib.readthedocs.io/en/latest/events.html
Can you provide an example of how to authenticate with Google using existing functionality in grpclib I mentioned above? Maybe I can add more helpers into grpclib and/or document this properly with examples.
I'm trying to use the auth token method. However with and without a token I get the following error (<Status.UNIMPLEMENTED: 12>, "Received :status = '404'")
.
Proto File - which I have regenerated using the python3 -m grpc_tools.protoc -I. --python_out=. --mypy_out=. --python_grpc_out=. cloud_speech.proto
import asyncio
import grpc
import wave
from grpclib.client import Channel, Stream
from cloud_speech_grpc import SpeechStub
from cloud_speech_pb2 import (
RecognitionConfig,
RecognitionAudio,
RecognizeRequest,
)
from gjwt import get_token
class GoogleGrpcClient():
def __init__(
self, loop: asyncio.AbstractEventLoop
) -> None:
self.channel = Channel("speech.googleapis.com",
"443", ssl=True, loop=loop)
fn = ./creds.json"
err, token = get_token(fn)
self.token = token
@property
def _grpc_stub(self):
return SpeechStub(self.channel)
@property
def grpc_config(self) -> RecognitionConfig:
return RecognitionConfig(encoding=1,
sample_rate_hertz=16000,
language_code="en-GB"
)
def grpc_audio(self, audio: bytes) -> RecognitionAudio:
return RecognitionAudio(content=audio)
async def recognize(self, audio: bytes) -> str:
return await self._grpc_stub.Recognize(
RecognizeRequest(
config=self.grpc_config,
audio=self.grpc_audio(audio),
),
metadata={"authorization": "Bearer " + self.token}
)
async def get_transcription():
fn = "../trimmed.wav"
fp = wave.open(fn)
frames = fp.getnframes()
data = fp.readframes(frames)
loop = asyncio.get_event_loop()
client = GoogleGrpcClient(loop)
try:
resp = await client.recognize(data)
print("RESPONSE", resp)
except Exception as e:
print("ERROR", e)
loop = asyncio.get_event_loop()
loop.run_until_complete(get_transcription())
Turns out that Google detects gRPC protocol by reading content-type header:
- I'm getting
:status 404
when I sendcontent-type application/grpc+proto
- I'm getting proper
grpc-status
when I sendcontent-type application/grpc
But gRPC protocol says that both variants are valid: https://github.com/grpc/grpc/blob/master/doc/PROTOCOL-HTTP2.md
Unfortunately grpclib doesn't allow you to set your custom content-type header value.