'Trouble validating JWT access token in python cloud function
I am trying to add authorization to my python Cloud Functions. I created a service account in the GCP project and generated keys. The test client code (not in GCP) to call the Cloud Function looks like this:
from google.oauth2 import service_account
from google.auth.transport.requests import AuthorizedSession
SERVICE_ACCOUNT_FILE = '<my_project_key_file>.json'
credentials = service_account.Credentials.from_service_account_file(SERVICE_ACCOUNT_FILE,
scopes=['https://www.googleapis.com/auth/userinfo.email'])
authed_session = AuthorizedSession(credentials)
response = authed_session.get('https://<my_project>.cloudfunctions.net/authValidation')
I know this code correctly gets the JWT bearer token from Google and is added to the Authorization header in the call to my Cloud Function. I'm just having a hard time validating that token in the Cloud Function. The relevant part of that code looks like this:
from google.oauth2 import id_token
from google.auth.transport import requests
def hello_world(request):
# from https://developers.google.com/identity/sign-in/web/backend-auth#using-a-google-api-client-library
idinfo = id_token.verify_oauth2_token(request.headers.get('Authorization')[7:]), requests.Request())
I know the id token is correct because the manual validation (using https://www.googleapis.com/oauth2/v1/tokeninfo?access_token=xxx ) returns exactly what I would expect.
The error logging stacktrace I get is:
Traceback (most recent call last):
File "/env/local/lib/python3.7/site-packages/google/cloud/functions/worker.py", line 346, in run_http_function
result = _function_handler.invoke_user_function(flask.request)
File "/env/local/lib/python3.7/site-packages/google/cloud/functions/worker.py", line 217, in invoke_user_function
return call_user_function(request_or_event)
File "/env/local/lib/python3.7/site-packages/google/cloud/functions/worker.py", line 210, in call_user_function
return self._user_function(request_or_event)
File "/user_code/main.py", line 17, in hello_world
idinfo = id_token.verify_oauth2_token(request.headers.get('Authorization')[7:], requests.Request())
File "/env/local/lib/python3.7/site-packages/google/oauth2/id_token.py", line 141, in verify_oauth2_token
certs_url=_GOOGLE_OAUTH2_CERTS_URL)
File "/env/local/lib/python3.7/site-packages/google/oauth2/id_token.py", line 122, in verify_token
return jwt.decode(id_token, certs=certs, audience=audience)
File "/env/local/lib/python3.7/site-packages/google/auth/jwt.py", line 219, in decode
header, payload, signed_section, signature = _unverified_decode(token)
File "/env/local/lib/python3.7/site-packages/google/auth/jwt.py", line 139, in _unverified_decode
header = _decode_jwt_segment(encoded_header)
File "/env/local/lib/python3.7/site-packages/google/auth/jwt.py", line 112, in _decode_jwt_segment
six.raise_from(new_exc, caught_exc)
File "<string>", line 3, in raise_from
ValueError: Can't parse segment: b'\xc9\xad\xbd'
What am I missing here? Thanks
Solution 1:[1]
By setting the GOOGLE_APPLICATION_CREDENTIAL environment variable in your local system, your client will run under the context of that service account without having to worry about auth. You don't need to code the path to the keyfile.
Also applies to deploying the Cloud Function, and testing it locally. When you deploy a Cloud Function, it runs as the AppEngine default service account, or the service account you specify with the --service-account parameter: https://cloud.google.com/sdk/gcloud/reference/functions/deploy
Reference: https://cloud.google.com/docs/authentication/production
This way you don't need to push the key to the server or worry about it in git, and you also don't need to make any code changes while running locally vs remotely.
Solution 2:[2]
Make sure the string passed to id_token.verify_oauth2_token() does not have the "Bearer " still at the start of it.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | JGC |
| Solution 2 | Brian C. |
