2

I have followed this really simple guide: https://cloud.google.com/text-to-speech/docs/quickstart-client-libraries?hl=en

I have found no problems following the steps with python, but when I execute the example code this error appears:

/usr/bin/env /usr/bin/python /home/edoelas/.vscode/extensions/ms-python.python-2021.1.502429796/pythonFiles/lib/python/debugpy/launcher 41413 -- /home/edoelas/git/gsdeck/scripts/generateaudio.py 
Traceback (most recent call last):
  File "/home/edoelas/.local/lib/python3.9/site-packages/google/api_core/grpc_helpers.py", line 73, in error_remapped_callable
    return callable_(*args, **kwargs)
  File "/home/edoelas/.local/lib/python3.9/site-packages/grpc/_channel.py", line 923, in __call__
    return _end_unary_response_blocking(state, call, False, None)
  File "/home/edoelas/.local/lib/python3.9/site-packages/grpc/_channel.py", line 826, in _end_unary_response_blocking
    raise _InactiveRpcError(state)
grpc._channel._InactiveRpcError: <_InactiveRpcError of RPC that terminated with:
        status = StatusCode.UNAVAILABLE
        details = "Getting metadata from plugin failed with error: ('invalid_grant: Invalid JWT: Token must be a short-lived token (60 minutes) and in a reasonable timeframe. Check your iat and exp values in the JWT claim.', '{"error":"invalid_grant","error_description":"Invalid JWT: Token must be a short-lived token (60 minutes) and in a reasonable timeframe. Check your iat and exp values in the JWT claim."}')"
        debug_error_string = "{"created":"@1612972534.048677552","description":"Getting metadata from plugin failed with error: ('invalid_grant: Invalid JWT: Token must be a short-lived token (60 minutes) and in a reasonable timeframe. Check your iat and exp values in the JWT claim.', '{"error":"invalid_grant","error_description":"Invalid JWT: Token must be a short-lived token (60 minutes) and in a reasonable timeframe. Check your iat and exp values in the JWT claim."}')","file":"src/core/lib/security/credentials/plugin/plugin_credentials.cc","file_line":90,"grpc_status":14}"
>

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "/home/edoelas/git/gsdeck/scripts/generateaudio.py", line 27, in <module>
    response = client.synthesize_speech(
  File "/home/edoelas/.local/lib/python3.9/site-packages/google/cloud/texttospeech_v1/services/text_to_speech/client.py", line 374, in synthesize_speech
    response = rpc(request, retry=retry, timeout=timeout, metadata=metadata,)
  File "/home/edoelas/.local/lib/python3.9/site-packages/google/api_core/gapic_v1/method.py", line 145, in __call__
    return wrapped_func(*args, **kwargs)
  File "/home/edoelas/.local/lib/python3.9/site-packages/google/api_core/grpc_helpers.py", line 75, in error_remapped_callable
    six.raise_from(exceptions.from_grpc_error(exc), exc)
  File "<string>", line 3, in raise_from
google.api_core.exceptions.ServiceUnavailable: 503 Getting metadata from plugin failed with error: ('invalid_grant: Invalid JWT: Token must be a short-lived token (60 minutes) and in a reasonable timeframe. Check your iat and exp values in the JWT claim.', '{"error":"invalid_grant","error_description":"Invalid JWT: Token must be a short-lived token (60 minutes) and in a reasonable timeframe. Check your iat and exp values in the JWT claim."}')

I do not have any experience with google cloud APIs. I don't know when the JWT is being generated or if the problem is there. I also have checked the time of my system and it looks fine unless I have to set a different time to match the one in the google cloud console or something like that.

EDIT: I did not use the service account to authenticate manually anywhere, I just set the environment variable GOOGLE_APPLICATION_CREDENTIALS as said in the guide.

The step I think I could be doing something weird is when initializing the Cloud SDK. I just go to the terminal, write gcloud init create a new configuration, choose the google account from which I created this service account, choose the project where the service account is and that's all.

I did not set a venv since as far as I know that is just useful to isolate the python libraries.

The code is the same that is used in the guide:

"""Synthesizes speech from the input string of text or ssml.

Note: ssml must be well-formed according to:
    https://www.w3.org/TR/speech-synthesis/
"""
from google.cloud import texttospeech

# Instantiates a client
client = texttospeech.TextToSpeechClient()

# Set the text input to be synthesized
synthesis_input = texttospeech.SynthesisInput(text="Hello, World!")

# Build the voice request, select the language code ("en-US") and the ssml
# voice gender ("neutral")
voice = texttospeech.VoiceSelectionParams(
    language_code="en-US", ssml_gender=texttospeech.SsmlVoiceGender.NEUTRAL
)

# Select the type of audio file you want returned
audio_config = texttospeech.AudioConfig(
    audio_encoding=texttospeech.AudioEncoding.MP3
)

# Perform the text-to-speech request on the text input with the selected
# voice parameters and audio file type
response = client.synthesize_speech(
    input=synthesis_input, voice=voice, audio_config=audio_config
)

# The response's audio_content is binary.
with open("output.mp3", "wb") as out:
    # Write the response to the output file.
    out.write(response.audio_content)
    print('Audio content written to file "output.mp3"')

EDIT 2:

When following the CLI quick start guide, when I run the command:

curl -X POST \
-H "Authorization: Bearer "$(gcloud auth application-default print-access-token) \
-H "Content-Type: application/json; charset=utf-8" \
-d @request.json \
https://texttospeech.googleapis.com/v1/text:synthesize

I get:

ERROR: (gcloud.auth.application-default.print-access-token) There was a problem refreshing your current auth tokens: ('invalid_grant: Invalid JWT: Token must be a short-lived token (60 minutes) and in a reasonable timeframe. Check your iat and exp values in the JWT claim.', '{"error":"invalid_grant","error_description":"Invalid JWT: Token must be a short-lived token (60 minutes) and in a reasonable timeframe. Check your iat and exp values in the JWT claim."}')
Please run:

  $ gcloud auth application-default login

to obtain new credentials.
{
  "error": {
    "code": 403,
    "message": "The request is missing a valid API key.",
    "status": "PERMISSION_DENIED"
  }
}

And when running gcloud auth application-default login this is shown:

The environment variable [GOOGLE_APPLICATION_CREDENTIALS] is set to:
  [/home/edoelas/git/gsdeck/credentials/service_account.json]
Credentials will still be generated to the default location:
  [/home/edoelas/.config/gcloud/application_default_credentials.json]
To use these credentials, unset this environment variable before
running your application.

Do you want to continue (Y/n)?  Y    

Your browser has been opened to visit:

    https://accounts.google.com/o/oauth2/auth?response_type=code&client_id=764086051850-6qr4p6gpi6hn506pt8ejuq83di341hur.apps.googleusercontent.com&redirect_uri=http%3A%2F%2Flocalhost%3A8085%2F&scope=openid+https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fuserinfo.email+https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fcloud-platform+https%3A%2F%2Fwww.googleapis.com%2Fauth%2Faccounts.reauth&state=jAxmGRv50BQxjUy1acQvcs6Pyp2jNM&access_type=offline&code_challenge=gjZ5y5t3T7b2M0lhvL5Eqwhfag6i7c91oEjcc2Tw5CA&code_challenge_method=S256

Opening in existing browser session.

Credentials saved to file: [/home/edoelas/.config/gcloud/application_default_credentials.json]

These credentials will be used by any library that requests Application Default Credentials (ADC).
/opt/google-cloud-sdk/lib/third_party/google/auth/_default.py:69: UserWarning: Your application has authenticated using end user credentials from Google Cloud SDK without a quota project. You might receive a "quota exceeded" or "API not enabled" error. We recommend you rerun `gcloud auth application-default login` and make sure a quota project is added. Or you can use service accounts instead. For more information about service accounts, see https://cloud.google.com/docs/authentication/
  warnings.warn(_CLOUD_SDK_CREDENTIALS_WARNING)

Quota project "gsdeck" was added to ADC which can be used by Google client libraries for billing and quota. Note that some services may still bill the project owning the resource.
edoelas
  • 317
  • 2
  • 13
  • Did you used a [service account](https://cloud.google.com/text-to-speech/docs/quickstart-client-libraries?hl=en#before-you-begin) to authenticate? Before to run the example did you setting up a Python development environment as is mentioned in this[documentation](https://cloud.google.com/python/docs/setup#windows)? Please share the code you are using too. – Enrique Zetina Feb 10 '21 at 17:36
  • Also I recommend you to try with the [command line quick-start](https://cloud.google.com/text-to-speech/docs/quickstart-protocol?hl=en) and share the results here. – Enrique Zetina Feb 10 '21 at 17:42
  • Edited the main post with your suggestions. – edoelas Feb 10 '21 at 18:03
  • Usually ‘missing a valid API key’ indicates that you didn’t set up the authentication for the service account which is used to make an API call. If you’ve followed all the steps exactly as mentioned, you should have had a JSON file downloaded by the end of Step 4, choose the right operating system you’re using and check step 5 to set the environment variable GOOGLE_APPLICATION_CREDENTIALS to the file path of the JSON file that contains your service account key. Opening a new session without setting the variable again or inputting a wrong path could lead to the error you’ve got. – Enrique Zetina Feb 10 '21 at 18:07
  • take a look in this [post](https://stackoverflow.com/a/38632272/10409068) you can try the workaround provided there – Enrique Zetina Feb 10 '21 at 19:08

1 Answers1

6

One of the primary reasons that I've seen in JWT tokens is the server generating the token is out of sync with the client to which it is trying to communicate to.

Could you please ensure that your system's time is in sync and also is configured to keep itself updated to a NTP server ?

DhakkanCoder
  • 794
  • 3
  • 15
  • Could it be because my system locale has LC_TIME="en_GB.UTF-8" but I do not live there and I adjusted my system time to be the same as where I live? – edoelas Feb 10 '21 at 18:24
  • So if you're not in the timezone which is set on the system and you've manually updated that to your time, then that actually isn't a correct way to do so since the timezone would still be UTC `-8`. And when JWT tokens are to be generated, they would generate the token with epoch i.e. `UTC+0`, which would lead to a skew on the time that you've configured to the actual current UTC time. That would lead to either the token being from future or past. I would recommend you to change your timezone followed by correcting your time. Please let me know the base OS if you want help to configure this. – DhakkanCoder Feb 10 '21 at 18:36
  • I am working with Arch linux. I have changed the LC_TIME var to es_ES.UTF-8 (my country) but the problem still persist. – edoelas Feb 10 '21 at 18:46
  • https://wiki.archlinux.org/index.php/System_time should help you understand the time configuation. – DhakkanCoder Feb 10 '21 at 18:52
  • 1
    Oh my god, it was the time, I had so many things messed up related to the time in my system. Thanks, I will mark your question as the solution. I ended up changing the system time zone and using the answer to this question: https://unix.stackexchange.com/questions/60772/i-messed-up-my-system-clock-in-arch-linux to sincronize with the exact time of my region. – edoelas Feb 10 '21 at 19:15
  • Glad I could be to your help. Thanks for posting the reference which helped you fix it :) – DhakkanCoder Feb 10 '21 at 19:22