Making authenticated request to Google Cloud Function - ruby

I have Google Cloud Function which is acceble on https://us-central1-project.cloudfunctions.net/update
Also I have Service Account with role 'Invoke Google Cloud Function'
First, I need to authenticate request, for this I'm using https://github.com/googleapis/google-auth-library-ruby
I've created google_cloud.json for my Service Account, I'm doing
credentials = Google::Auth::ServiceAccountJwtHeaderCredentials.make_creds({json_key_io: File.open('./config/google_cloud.json'), scope: 'https://www.googleapis.com/auth/
cloud-platform'})
headers = {}
credentials.apply(headers)
output looks like
{:authorization=>"Bearer ENCODED_TOKEN"}
then I'm doing
curl -X POST -H "Authorization: Bearer ENCODED_TOKEN" -H 'Content-Type: application/json' -d '{"data":["user1"]}' "https://us-central1-project.cloudfunctions.net/update"
And it return HTML with
<h2>Your client does not have permission to the requested URL <code>/update_statuses</code>.</h2>
If I have a VPS server that should do API requests to Google Cloud Function, how should I authorize it?

As mentioned by #DazWilkin, enable the service account by running gcloud auth print-identity-token then to get an identity token, you can gcloud auth print-identity-token --account=${ACCOUNT} where ACCOUNT is the email address of the service account.
You may refer to official documentation for more details.

I've got it finally. Code in the question should be used to get Access Token, but for calling Google Cloud Functions I need ID Token. For that, instead of the scope we need to pass function url as target_audience
google_url = 'https://us-central1-project.cloudfunctions.net/update'
path = File.join(__dir__, '../config/google_cloud.json')
authorizer = Google::Auth::ServiceAccountCredentials.make_creds(json_key_io: File.open(path), target_audience: google_url)
token = authorizer.apply({})[:authorization]

Related

Error 400: invalid_scope Some requested scopes cannot be shown: [https://www.googleapis.com/auth/homegraph]

So I'm trying to use the Home Graph API by calling the API endpoint
https://homegraph.googleapis.com/v1/devices:requestSync
It is a HTTP POST request and it needs an ACCESS_TOKEN and service account key.
Getting the service account key is easily done as per Google's documentation. The issue is getting the ACCESS_TOKEN.
As per this documentation by Google, I need to get ACCESS_TOKEN created using the following scope of permissions
https://www.googleapis.com/auth/homegraph
I opened OAuth 2.0 Playground to request a developer temporary ACCESS_TOKEN for testing. I wrote all the necessary urls and in scope I wrote this-
scope is written to be authorized
Now after this, I am navigated to my Authorization URL (ie, Google's sign in page). I login with email id and password.
If credentials are correct and scope mentioned is valid then I should have been redirected to OAuth playground page with authorization code which I would have exchanged for access token and refresh token.
But, what actually happens is after I enter my credentials, I get following error and I am never redirected to Oauth Playground page-
Authorization Error
Error 400: invalid_scope
Some requested scopes cannot be shown: [https://www.googleapis.com/auth/homegraph]
Request Details
access_type=offline
o2v=2
response_type=code
redirect_uri=https://developers.google.com/oauthplayground
prompt=consent
client_id=xxxxxxxxx.apps.googleusercontent.com
scope=https://www.googleapis.com/auth/homegraph**
I searched a lot online too, but couldn't find the actual reason.
So due to this issue with scope, I am not able to get ACCESS_TOKEN.
I have followed Google's documentation and the scope was mentioned there.
This is the pic from oauth 2.0 playground settings- OAuth 2.0 configuration
The issue is that you, a user, should not be getting and sending an access token. The service account should be getting and sending an access token. This is to make sure your service is authorized to talk to the Home Graph API.
You indicated you logged into the OAuth playground with "userid and password". But service accounts don't have passwords.
If you are using one of Google's libraries, it will take care of getting the access token for you, and this is the easiest way to do so. If you are just testing and need an access token, you can use something like oauth2l to get the access token based on the service account credentials.
I had implemented the REST approach to call HomeGraph Report State as below.
We need to follow the below steps:
Create a service account for your project and safely store the json file
Using the service account JSON, get the access token from Google
Using Oauth 2.0 token as Bearer authorization, invoke Report State API
Step 1:
This is straightforward. Please follow the steps in the below link
https://developers.google.com/assistant/smarthome/develop/report-state#expandable-1
Step 2:
Refer below code to get the Access token using service account json
GoogleCredentials credentials = GoogleCredentials
.fromStream(Helper.class.getClassLoader().getResourceAsStream("smart-home-key.json"))
.createScoped("https://www.googleapis.com/auth/homegraph");
credentials.refreshIfExpired();
AccessToken token = credentials.getAccessToken();
return token.getTokenValue();
Step 3:
Invoke Report State API
curl -X POST -H "Authorization: Bearer [[Access token from Step 2]]"
-H "Content-Type: application/json"
-d #request-body.json
"https://homegraph.googleapis.com/v1/devices:reportStateAndNotification"
Reference Links :
https://developers.google.com/assistant/smarthome/develop/report-state#http-post
https://cloud.google.com/endpoints/docs/openapi/service-account-authentication
https://developers.google.com/identity/protocols/oauth2/service-account#httprest_1
https://developers.google.com/assistant/smarthome/develop/report-state#expandable-1

try Google API Buckets: testIamPermissions for a specific service account

I can use Buckets: testIamPermissions to test the permissions on a bucket for the logged in user.
Is there a way in which I can test it for a service account.
Any help will be appreciated. Thanks...
After taking another look on your question, I found a way to use Buckets: testIamPermissions with a Service Account:
You have to download the service account’s key.json file in your environment (with gcloud set up) and create an environment variable with:
GOOGLE_APPLICATION_CREDENTIALS=[key.json]
Then, you can get a token of this service account via:
gcloud auth application-default print-access-token
Finally, you can curl the testIamPermissions URL and pass that token as authorization header:
curl 'https://www.googleapis.com/storage/v1/b/[BUCKET]/iam/testPermissions?permissions=[PERMISSION]' -H 'Authorization: Bearer [TOKEN]’
As described in Google documentation:
To see if a service account has access to a resource, call the getIamPolicy method on the target resource. For example, to view grants for a project, call the projects.getIamPolicy method.
So to check if a Service Account has access to a Bucket, you have to use Buckets: getIamPolicy specifying the Bucket you want to check.

Auth to Google Cloud Storage JSON API with Service Account from Postman

We are trying to use service account auth with our backend service to work with Google Cloud Storage JSON API. But cannot findout exactly how it should be done. We found examples for use with Client Libs but we are working with REST API. Can someone explain to me how to setup service account auth in POSTMAN?
I’m not sure how to set this up on POSTMAN but perhaps with the following information you can figure it out:
To authenticate with a service account to Storage API or any Google Cloud REST API you need to generate an OAuth Token and include it in your request headers. To accomplish this, you need the Cloud SDK, since you will print the token with the gcloud command. The steps are as follows:
Create a new service account and generate a JSON key file.
Copy the JSON key file and install Cloud SDK in the computer where you will make the API calls from.
Use the gcloud tool to activate the service account:
gcloud auth activate-service-account --key-file=/path/file.json
Generate an access token and save it to an environment variable:
ACCESS_TOKEN="$(gcloud auth print-access-token)"
Include the access token in your request headers,like this:
"Authorization: Bearer $ACCESS_TOKEN"
I was able to find this link on how to access environmental variables from POSTMAN and this one on how to set a Bearer token, hopefully they'll help as well.

Spring Security OAuth2 JWT anonymous token

What I Did
First I accept that I am lacking in spring security knowledge.
I am trying secure rest services for one of our product. I am using spring security OAuth2 JWT. I want to allow anonymous as well as registered users to access my resources.
Suppose I have one service "http://localhost:8282/melayer/articles" and when I run following command
(1). curl -X POST -vu melayer:12345 http://localhost:8282/melayer/oauth/token -H "Accept: application/json" -d "password=melayer&username=melayer&grant_type=password&scope=write&client_secret=12345&client_id=melayer"
I am able to receive access_token, refresh_token etc. Everything works fantastic, even I can access url http://localhost:8282/melayer/articles with received acces_token
(2). curl http://localhost:8282/melayer/articles -H "Authorization: Bearer eyJhbGciOiJIUzI1NiJ9.eyJleHAiOjE0NjA3NzY5NDIsInVzZXJfbmFtZSI6ImVjb2tyeXB0IiwianRpIjoiNWI5ZmE4NjYtMTBlNS00NDA2LTgxYmMtYjM3NWVmNGE0ZmQ1IiwiY2xpZW50X2lkIjoiZWNva3J5cHQiLCJzY29wZSI6WyJ3cml0ZSJdfQ.4jO9euBz4TSSNh7M3l2YBD1QPblE0ZyOfGm4VtyFMFY"
What I want to understand
I want to receive access_token anonymously i.e. I dont want to pass user name, password or client secret, I want to run curl command in following way
curl -X POST http://localhost:8282/melayer/oauth/token -H "Accept: application/json"
My one of the concern is, I want access_token with or without user credentials I am trying to achieve this from last week, Am I missing something ? is it possible ? what is correct way to do this ?
It is kind request to help me on this :)
If anyone want to see my code please refer Git repo https://github.com/aniruddhha/spring-security-oauth2-jwt
I think you Misunderstood the access token concept, access tokens are meant to be used on behalf of authenticated user.
OAuth2 supports different grants types (password, authorization_code, etc) , check the spec Oauth2 Spec
In order to authenticate used you can use any one of those grants or could create your own (eg: login with Google token ) but you must send some form of user credentials to identify the user and the client credentials to identify the client.
Access token cannot be used as some kind of ApiKey used to access public api

Google API refresh token CURL

I connecting the google spreadsheet API. I have already granted permission to the user and retrieved the code. I would like to refresh the token with the refresh token, but cannot find the url. can anyone point me to the url needed? I cannot use the libraries since I am using an ETL tool and not a code to connect to the service.
Thank you
Nir
This worked for me:
curl https://www.googleapis.com/oauth2/v4/token \
-d client_id=$CLIENT_ID \
-d client_secret=$CLIENT_SECRET \
-d refresh_token=$REFRESH_TOKEN \
-d grant_type=refresh_token
For the first authorization code exchange, a refresh token is obtained in offline scenarios. In these cases, your application may obtain a new access token by sending a refresh token to the Google OAuth 2.0 Authorization server.
As discussed in the documentation, to obtain a new access token, your application sends an HTTPS POST request to https://www.googleapis.com/oauth2/v4/token.

Resources