Gitkit token service API returns 403 "cannot be identified with a client project" error - google-identity-toolkit

I am currently trying to use the Google Identity Toolkit Token Service REST API (https://developers.google.com/identity/toolkit/reference/securetoken/rest/v1/token) to generate an access token which I can use in my backend server.
When I specifying "authorization_code" as "grant_type" and the gtoken cookie value after authentication as "code" in the POST request to https://securetoken.googleapis.com/v1/token, I get a 403 response with the following error message:
{
"error": {
"code": 403,
"message": "The request cannot be identified with a client project. Please pass a valid API key with the request.",
"status": "PERMISSION_DENIED"
}
}
I inspected the gtoken value via a JWT decoder and it looks to be correct in format. In particular I can see that aud is set to my application/client ID. The documentation doesn't say anything about specifying API key - usually I would expect that to be specified in the Authorization header. So I am not sure what I am missing here.
Any pointer to this matter would be appreciated.

An API key in the URL is required when calling Google Identity Toolkit APIs (including the Token Service API). However, I would suggest you take a look at the new version of the service - Firebase Authentication. The Firebase Auth SDK has build-in support of the Token Service API.

Related

FCM Push - Request had invalid authentication credentials. Expected OAuth 2 access token, login cookie or other valid authentication credential

I am trying to send fcm message to specific topic by using cURL command but it says error like
{
"error": {
"code": 401,
"message": "Request had invalid authentication credentials. Expected OAuth 2 access token, login cookie or other valid authentication credential. See https://developers.google.com/identity/sign-in/web/devconsole-project.",
"status": "UNAUTHENTICATED"
}
}
I used server key from firebase console
I followed this FCM Documentation
How to resolve this 401 error.
Actually I think why, this is because you need a Service account that will handle it for you.
So follow the steps here and this will make you generate a new key pair. With this key, you can get the access token from a code (see in python below but the documentation has support for NodeJS / Java) :
def _get_access_token():
"""Retrieve a valid access token that can be used to authorize requests.
:return: Access token.
"""
credentials = ServiceAccountCredentials.from_json_keyfile_name(
'service-account.json', SCOPES)
access_token_info = credentials.get_access_token()
return access_token_info.access_tokenmessaging.py
And you just have to print this value, copy-paste it and use it as the Bearer OAuth 2 access token.

Access API using Service Account

Does the Smart Device Management API support access using a Service Account? If so what's the magic combo?
I can access the API using registered OAuth2, and get valid device list response.
When using Service Account credentials to access the device list API I get:
{
"error": {
"code": 404,
"message": "Enterprise enterprises/{project-id} not found.",
"status": "NOT_FOUND"
}
}
I think the problem is that google have chosen to cut off the "home project" user. They seem to only support oauth2 auth and if you want to use it you have to get your app certified, otherwise they revoke the refresh token after 7 days. If the refresh token didn't get revoked every 7 days then I'd be happy with oauth2 offline auth. Come on google, support the home hobbyists!

Firebase Cloud Function HTTP Request Authorization

I have a scenario where I need to do a secure request a Firebase Cloud Function from an external server using a HTTP request. In order to request it I need to send a bearer JWT token on the authorization header. After sometime looking at the Google documents to Firebase/GCP I've found many different ways to authenticate using google different APIs, but I'm kinda lost on it.
I know that I need to use a service account in order to identify the machine that is calling instead a common human-user credentials. I also know that the service account provides a JSON file that contains secure information to identify that service account, like the private key. By looking different docs I found this one that explains how to generate and request a token. After following those steps, I'm facing a 403 status when I try to call the cloud function using the resulting token.
I doubled checked the roles my service account has and I do have the ones the docs have pointed me.
Does anyone knows or have any suggestions how to proceed to have cloud function authorized calls by a machine (not human) interaction.
Edit 1:
As requested here I'm posting my JWT generator code:
const {
private_key_id,
private_key,
client_email,
} = require('./serviceAccount.json');
const jwt = require('jsonwebtoken');
const payload = {
"kid": private_key_id,
"iss": client_email,
"sub": client_email,
"iat": 1611257400,
"exp": 1611260940,
"aud": "https://oauth2.googleapis.com/token",
"target_audience": "https://<project- region>.cloudfunctions.net/helloWorld"
};
const token = jwt.sign(payload, private_key, { algorithm: 'RS256', header: {"alg":"RS256","typ":"JWT"} });
console.log(token);
With the result token from above I'm sending a POST request to https://oauth2.googleapis.com/token where the token is sent as the assertion field on a form data.
After suggestions here I did some research and found this blog with instructions to generate a Identity token using my service account. So I ran:
# Load the service account identity
gcloud auth activate-service-account --key-file=key.json
# Generate an id token
gcloud auth print-identity-token
The resulting token gave me the same result a 403 - Forbidden error. The interesting part is that using my user credentials and using gcloud to generate an identity token I was able to request the Cloud function with a 200 result.
I'm thinking that I'm missing some sort of role/privilege/scope on my service account configuration.
Make sure that the service account has assigned the cloudfunctions.functions.invoke in order to guarantee that the Cloud Function can be triggered from an external server using an HTTP request.

Firebase bearer token from OAuth2 playground

I'm trying to test my application that uses Firebase for push notifications using postman.
I'm specifically testing the Http v1 Api, and looking how to authorize the request.
What I need to get right is getting the OAuth2 token to use in Postman, which I should be able to do on the OAuth 2.0 playground although I'm not sure how.
I have my privatkey.json file that I've downloaded from the firebase console, I just need to know how to use it to get the token that I would add as a bearer authorization header for my POST requests
I was able to send a message through the FCM v1 HTTP API by requesting the following scopes in the OAuth2 playground:
email, https://www.googleapis.com/auth/firebase.messaging
After authorizing this, I exchanged the authorization code for refresh and access tokens.
I then passed the resulting access token into the call with FCM:
curl -X POST -H "Authorization: Bearer MY_ACCESS_TOKEN" -H "Content-Type: application/json" -d '{"message":{
"notification": {
"title": "FCM Message",
"body": "This is an FCM Message",
},
"token": "MY_DEVICE_TOKEN"
}
}' https://fcm.googleapis.com/v1/projects/MY_PROJECT_ID/messages:send
In the above CURL request replace the following placeholders with the relevant values for you:
MY_PROJECT_ID is the Firebase project ID, which you can get from the project settings page in the Firebase console
MY_DEVICE_TOKEN is the registration token of the device that you want to send the message to. For a web client, see how to get the current registration token.
MY_ACCESS_TOKEN is the OAuth2 access token that you got from the OAuth2 playground using the steps outlined above.
The FCM documentation on authenticating FCM v1 requests may be confusing since it only calls out the OAuth2 token. It actually first generates a self-signed JWT (JSON Web Token) by calling new google.auth.JWT(...). This involves downloading a private key, and generating the JWT locally through a JWT library.
The self-signed JWT is then passed to jwtClient.authorize(...), which gives back tokens including an access_token. The latter is an OAuth2 access token, similar to the one we got above.
I created a small project on hithub that includes both a postman collection and environment and nodejs project that uses the downloaded service-key.json to generate an access token which solves my problem above. It's not as elagent as using only postman (which to me seems impossible), but it works well enough since the access tokens live for about an hour.

How to invoke the BaaS API

I have created a new collection and have added few entities to this collection in the APIGEE BaaS. I am able to run GET query using the admin portal.
I am trying to invoke the same using my REST client.
I am using the following URL: https://api.usergrid.com/myOrg/myapp/mycollection
However, I get below error:
{
"error": "unauthorized",
"timestamp": 1401855388323,
"duration": 1,
"exception": "org.apache.shiro.authz.UnauthorizedException",
"error_description": "Subject does not have permission [applications:get:xxxxxxxxxxx]"
}
I believe I need to add authorization information in the HTTP header for the request. But am unable to find information on what is expected.
How can I invoke the BaaS API?
This is happening because you don't have permission to access the collection without authentication (or in some cases, your authentication token may not have appropriate permission to access that particular collection.
You can read about managing permissions & roles in the Apigee docs.
There are a couple quick ways to solve your problem though:
(The most prevalent) is to authenticate your user account and use an appropriate access token (e.g. https://api.usergrid.com/myOrg/myapp/mycollection?access_token=<token>)
While it's not something you should be doing on the client side, for server-side requests or testing purposes, you can use your app or org-level client_id/client_secret in a similar manner (e.g. https://api.usergrid.com/myOrg/myapp/mycollection?client_id=<id>&client_id=<secret>)
Give the Guest role access to your collection (here's a link to the docs)

Resources