The docs says that I can get the keys by this request:
POST https://iam.googleapis.com/v1/projects/PROJECT-ID/serviceAccounts/SA-NAME#PROJECT-ID.iam.gserviceaccount.com/keys
I created a service account.
For the example lets say:
SA-NAME = xxx
PROJECT-ID = yy-zz
When i do (Python)
import requests
url = 'https://iam.googleapis.com/v1/projects/yy-zz/serviceAccounts/xxx#yy-zz.iam.gserviceaccount.com/keys'
try:
g = requests.post(url, verify=True)
except requests.exceptions.HTTPError as err:
print err
sys.exit(1)
print g
I get:
<Response [403]>
What am I doing wrong?
You need to authenticate using OAuth2 to be able to use the service. The 403 error you're receiving is expected because your not authenticating before trying to use the service.
See the following links for some information on authenticating via these methods:
https://developers.google.com/identity/protocols/OAuth2
Authenticating to the service may look like the following:
from google.oauth2 import service_account
SCOPES = ['https://www.googleapis.com/auth/sqlservice.admin']
SERVICE_ACCOUNT_FILE = '/path/to/service.json'
credentials = service_account.Credentials.from_service_account_file(
SERVICE_ACCOUNT_FILE, scopes=SCOPES)
Related
I am having trouble sending an authenticated firestore REST API request from a cloud function. The request needs to have an oauth2 token in the header. I've followed the docs here https://cloud.google.com/functions/docs/securing/authenticating and tried the python function they provided, but that still does not give the right authentication. What has worked so far is copying the token from gcloud auth application-default print-access-token but that expires after an hour. Any ideas?
import urllib
import google.auth.transport.requests
import google.oauth2.id_token
def make_authorized_get_request(endpoint, audience):
"""
make_authorized_get_request makes a GET request to the specified HTTP endpoint
by authenticating with the ID token obtained from the google-auth client library
using the specified audience value.
"""
# Cloud Functions uses your function's URL as the `audience` value
# audience = https://project-region-projectid.cloudfunctions.net/myFunction
# For Cloud Functions, `endpoint` and `audience` should be equal
req = urllib.request.Request(endpoint)
auth_req = google.auth.transport.requests.Request()
id_token = google.oauth2.id_token.fetch_id_token(auth_req, audience)
req.add_header("Authorization", f"Bearer {id_token}")
response = urllib.request.urlopen(req)
return response.read()
The above function results in aurllib.error.HTTPError: HTTP Error 401: Unauthorized"
The solution in my case was to add datastore.importExportAdmin "Cloud Datastore Import Export Admin" role to the service account that would generate the token. And to use the code below to generate a token from credentials:
credentials = service_account.Credentials.from_service_account_file(
SERVICE_ACCOUNT_FILE, scopes=SCOPES)
request = google.auth.transport.requests.Request()
credentials.refresh(request)
https://cloud.google.com/firestore/docs/security/iam#roles
I have a cloud function with trigger type set to HTTP and also have a service account which is having permissions to Invoke the cloud function. I want to invoke the cloud function from a python script. I am using the following script to invoke the function:
from google.oauth2 import service_account
from google.auth.transport.urllib3 import AuthorizedHttp
credentials = service_account.Credentials.from_service_account_file('/path/to/service-account-credentials.json')
scoped_credentials = credentials.with_scopes(['https://www.googleapis.com/auth/cloud-platform'])
authed_http = AuthorizedHttp(scoped_credentials)
response = authed_http.request('GET', 'https://test-123456.cloudfunctions.net/my-cloud-function')
print(response.status)
I am getting Unauthorized ( 401 ) error in response. Is this the correct way of invocation?
To be able to call your cloud function you need an ID Token against a Cloud Functions end point
from google.oauth2 import service_account
from google.auth.transport.requests import AuthorizedSession
url = 'https://test-123456.cloudfunctions.net/my-cloud-function'
creds = service_account.IDTokenCredentials.from_service_account_file(
'/path/to/service-account-credentials.json', target_audience=url)
authed_session = AuthorizedSession(creds)
# make authenticated request and print the response, status_code
resp = authed_session.get(url)
print(resp.status_code)
print(resp.text)
I'm trying to access a secure cloud run service. If I try from my machine with the SDK it works fine:
curl --header "Authorization: Bearer $(gcloud auth print-identity-token)"
However, I can not get it to work using the Python API using the same service account, I've tried using google-auth to get an access token but that gives me a 401 authentication error. This is the code I am using to try to get a token:
import google.auth
import google.auth.transport.requests
scopes = ['https://www.googleapis.com/auth/cloud-platform']
creds, projects = google.auth.default(scopes=scopes)
auth_req = google.auth.transport.requests.Request()
creds.refresh(auth_req)
# then using creds.token
Looking at the docs: https://cloud.google.com/run/docs/authenticating/service-to-service#calling_from_outside_gcp it says to follow the sample code here: https://cloud.google.com/iap/docs/authentication-howto#iap_make_request-python I can't seem to follow the guide as it says to enable IAP but it seems that IAP is only for app engine and not cloud run?
Has anyone go any advice on this one?
Thanks
OK it seems that there is an IDTokenCredentials class that works for this as it uses Open ID Connect ID Tokens instead of OAuth 2.0 Access Tokens:
https://google-auth.readthedocs.io/en/latest/reference/google.oauth2.service_account.html
from google.oauth2 import service_account
from google.auth.transport.requests import AuthorizedSession
service_url = 'example.com'
key_file = 'key.json'
credentials = service_account.IDTokenCredentials.from_service_account_file(
key_file, target_audience=service_url)
authed_session = AuthorizedSession(credentials)
response = authed_session.get(service_url)
It's confusing as I don't see it in the docs and it's leading me to something else about IAP which I don't think is working with Cloud Run.
If you still want to obtain your ID token and not use method from Dan's response there is an updated code:
import requests
import google.auth
from google.oauth2 import service_account
from google.auth.transport.requests import AuthorizedSession
service_url = 'example.com'
key_file = 'key.json'
credentials = service_account.IDTokenCredentials.from_service_account_file(
key_file, target_audience=service_url)
request = google.auth.transport.requests.Request()
credentials.refresh(request)
token = credentials.token
print('ID Token:', token)
I always get 401 error trying to fetch Firebase resource and passing access token. I cannot get what am I doing wrong.
So I follow this manual: I created service account, then create ServiceAccountCredentials object, passing scope https://www.googleapis.com/auth/firebase. Then I get token from created object and pass it as access_token query parameter, as stated in docs, trying fetch data from my Firebase DB. But I keep getting 401 error (unauthorized). Token, by the way, seems to be invalid if check in tool like jsonwebtoken (probably I do something wrong there / provide incorrect secret?).
So, my code is like this:
import httplib2
from oauth2client.service_account import ServiceAccountCredentials
credentials = ServiceAccountCredentials.from_json_keyfile_name('/path/auth.json', scopes=['https://www.googleapis.com/auth/firebase'])
token = credentials.get_access_token().access_token
http = httplib2.Http()
result = http.request('https://my-project.firebaseio.com/srv.json?access_token=%s' % token)
And result body always is {"error" : "Unauthorized request."} along with 401 HTTP status code.
I think your scopes were not sufficient. Here is a end to end example I got working using credentials and the credentials.authorize http wrapper
from oauth2client.service_account import ServiceAccountCredentials
from httplib2 import Http
import json
_BASE_URL = 'https://my-app-id.firebaseio.com'
_SCOPES = [
'https://www.googleapis.com/auth/userinfo.email',
'https://www.googleapis.com/auth/firebase.database'
]
# Get the credentials to make an authorized call to firebase
credentials = ServiceAccountCredentials.from_json_keyfile_name(
_KEY_FILE_PATH, scopes=_SCOPES)
# Wrap the http in the credentials. All subsequent calls are authenticated
http_auth = credentials.authorize(Http())
def post_object(path, objectToSave):
url = _BASE_URL + path
resp, content = http_auth.request(
uri=url,
method='POST',
headers={'Content-Type': 'application/json'},
body=json.dumps(objectToSave),
)
return content
objectToPost = {
'title': "title",
'message': "alert"
}
print post_object('/path/to/write/to.json', objectToPost)
Im trying to use the youtube analytics API. I already have the access token of the channel stored in some db. In Php, you can build the client and just add the access token, client_id, client_secret then use the client to call youtube analytics.
In the python example however, I saw something like this:
flow = flow_from_clientsecrets(
CLIENT_SECRETS_FILE,
scope=' '.join(YOUTUBE_SCOPES),
message=MISSING_CLIENT_SECRETS_MESSAGE)
storage = Storage('%s-oauth2.json' % sys.argv[0])
credentials = storage.get()
if credentials is None or credentials.invalid:
credentials = run_flow(flow, storage, data)
http = credentials.authorize(httplib2.Http())
yt.analytics = build(
YOUTUBE_ANALYTICS_API_SERVICE_NAME,
YOUTUBE_ANALYTICS_API_VERSION,
http=http)
It authenticates the user using the browser. I don't need to go by that step since I already have the access_token stored in the db. The question is how to use that access_token in the build() function call so that I can proceed with the query below.
analytics_query_response = yt_analytics.reports().query(
ids='channel==',
metrics=options.metrics,
dimensions=options.dimensions,
start_date=options.start_date,
end_date=options.end_date,
max_results=options.max_results,
sort=options.sort,
).execute()
Unfortunately, the build function doesn't have an access_token parameter. Here are the docs.
You can also create your credentials object like this, though (which may be what you are looking for):
from oauth2client.client import GoogleCredentials
from oauth2client import GOOGLE_TOKEN_URI
access_token = YOUR_TOKEN
token_expiry = None
token_uri = GOOGLE_TOKEN_URI
user_agent = 'Python client library'
revoke_uri = None
credentials = GoogleCredentials(
access_token,
client_id,
client_secret,
refresh_token,
token_expiry,
token_uri,
user_agent,
revoke_uri=revoke_uri
)