Using Postman to access Google Indexing APIs - google-cloud-platform

I would like to test Google Indexing API with Postman.
I have already configured the api correctly on https://console.cloud.google.com/ for using it on a wordpress site with the plugin Instant indexing and everything works ok.
Now I simply want to do a POST call with Postman, in particular I did not found anything clear about the type of authentication (Oauth 2) to use for the call.
{
"error": {
"code": 401,
"message": "Request is missing required authentication credential. 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",
"details": [
{
"#type": "type.googleapis.com/google.rpc.ErrorInfo",
"reason": "CREDENTIALS_MISSING",
"domain": "googleapis.com",
"metadata": {
"method": "google.indexing.v3.UrlService.PublishUrlNotification",
"service": "indexing.googleapis.com"
}
}
]
}
}
Anyone can provide me an example? Thank you.

As stated in the comments, Google API's normally use OAuth2. Some exceptions might use an API key, but even then most of those still limit the data you can access with an API key versus what you can access using OAuth2
This particular API does indeed use OAuth2 as per the docs. This means you need an access token (as the error message states), so you will need to generate one.
Easiest would be to use a library for one of the many programming languages, as per the docs here.
I'll give a simple example in python as that is my preferred language. The following code uses the google-auth library (docs). It's the base library to deal with credential objects. You will need to download the JSON representation for the service account you created. See the relevant docs. Note that you should handle this file as if it were a password, same as with the access token itself, although the access token has a default lifetime of 3600 seconds, AKA 1h.
If you get an error message that the token is expired, create a new one. Read up on refresh tokens for that, but that's beyond the scope of this question.
Code was tested on a virtualenv for python 3.10
requirements.txt
google-auth
requests
main.py
from google.oauth2 import service_account
import google.auth.transport.requests
# create credentials object
creds= service_account.Credentials.from_service_account_file("/path/to/serviceaccount.json")
# we need a scoped credentials object as per
# https://developers.google.com/search/apis/indexing-api/v3/prereqs#requirements
scoped_creds = creds.with_scopes(['https://www.googleapis.com/auth/indexing'])
# create a request object for the refresh method
request = google.auth.transport.requests.Request()
# make the library do it's magic and get a token
scoped_creds.refresh(request)
print(scoped_creds.token)
This will print out an access token. (if it prints with dots (....) at the end, remove them.
Another easy option would be to (ab)use the gcloud command line tool. There's a couple of steps to this to get to work. You can use the cloud shell as an easy way to do this.
Download or copy the serviceaccount JSON file I mentioned above.
Activate the serviceaccount in gcloud using:
gcloud auth activate-service-account SERVICE_ACCOUNT#DOMAIN.COM --key-file=/path/key.json
Print the access token with this command:
gcloud auth print-access-token
The hard and masochistic way would be to use something like CURL or HTTPS requests manually to generate the token. Feel free to do so, but I'm just going to point you to the docs for that. It's a bit of a pain in the posterior.
You can test the token as explained in this answer.
Now that you have the access token, you can use it in POSTMAN by setting it in the header for the call. See this nice answer, but basically add the following request header key/value pair, replacing TOKEN with the generated token.
KEY: Authorization
VALUE: Bearer TOKEN

For anyone interested I managed to make it work by following these steps:
To obtain the authentication token with Postman first go to https://console.cloud.google.com/apis/credentials and in your web application ID client set https://oauth.pstmn.io/v1/callback as Authorized redirect URIs
Now in Postman Application in Authorization tab select OAuth 2.0 and configure the fields according to your client_secret.json (image)
Now click on 'Get new access Token' and you should get it
Specify the url and type as raw json body (image)

Related

Microsoft Graph - CompactToken parsing failed with error code: 8004920A

I am requesting access token from Microsoft Graph using this procedure:
I request access to the following scopes:
User.Read.All openid profile email offline_access https://outlook.office.com/IMAP.AccessAsUser.All https://outlook.office.com/POP.AccessAsUser.All https://outlook.office.com/SMTP.Send
After the consent screen in web browser, the redirection occurs and the codes are sent to temporary localhost web server running on user's PC.
The code received is exchanged for access_token and refresh_token
When I try to query Microsoft Graph for user's profile I query:
GET https://graph.microsoft.com/v1.0/me
Header of the GET request contains:
Authorization: Bearer token-here-all-in-one-line
But I get the resulting JSON:
"InvalidAuthenticationToken"
"CompactToken parsing failed with error code: 8004920A"
I would normally assume the token is not correct, but I tested the same token from C++ app and a small PHP app, and I always test the same error. To be sure that it is not the wrong token, I deliberately modify it to a wrong token and then I get:
"CompactToken parsing failed with error code: 80049217"
After googling - 8004920A means "token rejected" (the error I have problem with) and 80049217 means "malformed token" so that is consistent with me deliberately inserting false data as token.
So I would assume that the token is correct but Microsoft Graph rejects it to query user profile information which is consented and approved.
I have tested the token on IMAP and SMTP access and there it works - mails are sent and received, so the access_token is definitely good.
Any ideas why Microsoft Graph rejects my attempt to query user profile?
Do I need to enable something when registering application in AzureAD portal?
I am doing this from C++ or from PHP so I don't think the code is of relevance here.
Not sure if this is the case, but it may be. You cannot use the same token for graph access and another API acccess (such as Outlook REST api, in your case). Meaning, you cannot mix scopes from different namespaces. Not sure why ("by design"?), you just can't. You need two separate tokens.
I faced similar issue with SharePoint REST api access (so may not be 100% sure it is also true for Outlook as well, but probably it is). I used a relatively easy way out - exchanging the token requested for openid profile email offline_access for token for https://outlook.office.com/... on my server (using the on_behalf_of flow).
If you don't really need the graph scope User.Read.All you could also try simply removing that one from your first authorization call that obtains the token.
As #Nikolay has stated, the tokens for Graph and Outlook can't be mixed. And Microsoft has designed it poorly so that IMAP.AccessAsUser.All for example can't be used for IMAP access - the access_token simply won't work unless the https://outlook.office.com/ prefix is added.
But - I found another way, which works for just reading the user's profile and email address which is by decoding the id_token. As Microsoft documentation states - openid profile and email scopes will work with both Graph and Outlook. profile token can be used to extract the information about user's profile.
As explained on:
https://learn.microsoft.com/en-us/azure/active-directory/develop/id-tokens
id_token contains information such as email address, name etc.
A sample ID token from their page is:
eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImtpZCI6IjFMVE16YWtpaGlSbGFfOHoyQkVKVlhlV01xbyJ9.eyJ2ZXIiOiIyLjAiLCJpc3MiOiJodHRwczovL2xvZ2luLm1pY3Jvc29mdG9ubGluZS5jb20vOTEyMjA0MGQtNmM2Ny00YzViLWIxMTItMzZhMzA0YjY2ZGFkL3YyLjAiLCJzdWIiOiJBQUFBQUFBQUFBQUFBQUFBQUFBQUFJa3pxRlZyU2FTYUZIeTc4MmJidGFRIiwiYXVkIjoiNmNiMDQwMTgtYTNmNS00NmE3LWI5OTUtOTQwYzc4ZjVhZWYzIiwiZXhwIjoxNTM2MzYxNDExLCJpYXQiOjE1MzYyNzQ3MTEsIm5iZiI6MTUzNjI3NDcxMSwibmFtZSI6IkFiZSBMaW5jb2xuIiwicHJlZmVycmVkX3VzZXJuYW1lIjoiQWJlTGlAbWljcm9zb2Z0LmNvbSIsIm9pZCI6IjAwMDAwMDAwLTAwMDAtMDAwMC02NmYzLTMzMzJlY2E3ZWE4MSIsInRpZCI6IjkxMjIwNDBkLTZjNjctNGM1Yi1iMTEyLTM2YTMwNGI2NmRhZCIsIm5vbmNlIjoiMTIzNTIzIiwiYWlvIjoiRGYyVVZYTDFpeCFsTUNXTVNPSkJjRmF0emNHZnZGR2hqS3Y4cTVnMHg3MzJkUjVNQjVCaXN2R1FPN1lXQnlqZDhpUURMcSFlR2JJRGFreXA1bW5PcmNkcUhlWVNubHRlcFFtUnA2QUlaOGpZIn0.1AFWW-Ck5nROwSlltm7GzZvDwUkqvhSQpm55TQsmVo9Y59cLhRXpvB8n-55HCr9Z6G_31_UbeUkoz612I2j_Sm9FFShSDDjoaLQr54CreGIJvjtmS3EkK9a7SJBbcpL1MpUtlfygow39tFjY7EVNW9plWUvRrTgVk7lYLprvfzw-CIqw3gHC-T7IK_m_xkr08INERBtaecwhTeN4chPC4W3jdmw_lIxzC48YoQ0dB1L9-ImX98Egypfrlbm0IBL5spFzL6JDZIRRJOu8vecJvj1mq-IUhGt0MacxX8jdxYLP-KUu2d9MbNKpCKJuZ7p8gwTL5B7NlUdh_dmSviPWrw
The token consists of 3 parts - header, payload and the signature. They are separated by a dot. That's a standard JWT (JSON Web Token) See details at - https://en.wikipedia.org/wiki/JSON_Web_Token
After separating them and then base64 decoding each (the signature doesn't give anything useful after decoding) the result is:
1) The header
{
"typ": "JWT",
"alg": "RS256",
"kid": "1LTMzakihiRla_8z2BEJVXeWMqo"
}
2) The payload
Payload which contains the user info. Additional information can be extracted by adding Optional claims when registering app in Azure AD - (Token configuration in the menu on the left).
{
"ver": "2.0",
"iss": "https://login.microsoftonline.com/9122040d-6c67-4c5b-b112-36a304b66dad/v2.0",
"sub": "AAAAAAAAAAAAAAAAAAAAAIkzqFVrSaSaFHy782bbtaQ",
"aud": "6cb04018-a3f5-46a7-b995-940c78f5aef3",
"exp": 1536361411,
"iat": 1536274711,
"nbf": 1536274711,
"name": "Abe Lincoln",
"preferred_username": "AbeLi#microsoft.com",
"oid": "00000000-0000-0000-66f3-3332eca7ea81",
"tid": "9122040d-6c67-4c5b-b112-36a304b66dad",
"nonce": "123523",
"aio": "Df2UVXL1ix!lMCWMSOJBcFatzcGfvFGhjKv8q5g0x732dR5MB5BisvGQO7YWByjd8iQDLq!eGbIDakyp5mnOrcdqHeYSnltepQmRp6AIZ8jY"
}
3) The signature
For verification purposes only.
1AFWW-Ck5nROwSlltm7GzZvDwUkqvhSQpm55TQsmVo9Y59cLhRXpvB8n-55HCr9Z6G_31_UbeUkoz612I2j_Sm9FFShSDDjoaLQr54CreGIJvjtmS3EkK9a7SJBbcpL1MpUtlfygow39tFjY7EVNW9plWUvRrTgVk7lYLprvfzw-CIqw3gHC-T7IK_m_xkr08INERBtaecwhTeN4chPC4W3jdmw_lIxzC48YoQ0dB1L9-ImX98Egypfrlbm0IBL5spFzL6JDZIRRJOu8vecJvj1mq-IUhGt0MacxX8jdxYLP-KUu2d9MbNKpCKJuZ7p8gwTL5B7NlUdh_dmSviPWrw

How to convert Amazon MWS credentials to SP-API creds

Here are the seemingly clear instructions from Amazon.
Simply send the following: sellingPartnerId, developerId, and mwsAuthToken
I do this with httparty like so:
query = {
sellingPartnerId: "A3Kxxxxx",
developerId: "753xxxx",
mwsAuthToken: "amzn.mws.8abxxxxx-xxxx-xxxx-xxxx-xxxxxx",
}
and then
send = HTTParty.get("https://sellingpartnerapi-na.amazon.com/authorization/v1/authorizationCode",
query: query
)
This returns the following error:
{"errors"=>
[{"message"=>"Access to requested resource is denied.",
"code"=>"MissingAuthenticationToken"}]}
I've adjusted the call everyway I've seen. I've read the following articles:
This
This
Paged through the 695 issues on github for this API and still no luck.. I've adjusted my query to this with no luck either:
query = {
grant_type: "client_credentials",
sellingPartnerId: "A3K98Oxxxxxx",
developerId: "753xxxxxxxx",
mwsAuthToken: "amzn.mws.8abxxxxxxx-xxxx-xxxx-xxxx-xxxxxxx",
client_id: "amzn1.application-oa2-client.xxxxxxxxxxxxxxxxxxxxxxxx",
client_secret: "a473e76XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
scope: "sellingpartnerapi::migration"
}
Nothing I've tried has worked.. Any suggestions? Has anyone actually migrated their MWS to SP-API credential successfully?
Unfortunately the specific Amazon docs that you link to don't tell the whole story. There are a few other requirements you'll need in order to get the authorizationCode response that you're looking for:
Amazon OAuth Token
You'll need an access token from Amazon's OAuth API (an entirely different API). You can use the grantless workflow for this, since in your case the user hasn't actually authorized the SP-API yet:
POST https://api.amazon.com/auth/o2/token
body: {
grant_type: 'client_credentials',
scope: 'sellingpartnerapi::migration',
client_id: 'amzn1.application-oa2-client.xxxxxxxxxxxxxxxxxxxxxxxx',
client_secret: 'a473e76XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'
}
This will return an access_token that you'll need for your actual migration request to https://sellingpartnerapi-na.amazon.com/authorization/v1/authorizationCode. The response will look something like:
{
"access_token": "Atc|xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
"scope": "sellingpartnerapi::migration",
"token_type": "bearer",
"expires_in": 3600
}
Important: Take the access_token value from that response and add it as an x-amz-access-token header to your /authorization/v1/authorizationCode request.
Sign Your Request
This is the actual reason behind the error you're receiving. An unsigned request will not include the "authorization token" that you're being prompted for.
You'll need to sign your request using Amazon's SigV4 signing mechanism. It looks like you're using Ruby (HTTParty), so you can use the aws-sdk's Aws::Sigv4::Signer for this. You'll need to have setup IAM credentials as documented in the generic developer guide, and those credentials being provided to your Aws::Sigv4::Signer somehow (hardcoding, env vars, Aws::SharedCredentials, etc.)
Request signing will result in a few proprietary headers being added to your request. Once this is done, you should have all that you need to make the request successfully.

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

I am a novice developer who wants to learn how to use artificial intelligence.
So I created model and it responds correctly according to the inputs.
So I want to test using postman a call to the API to verify that everything works and I have an error in my call:
"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 don't know how to authenticate myself to retrieve the access token. Could you help me find a solution please?
You have 2 solutions:
As John commented,
Install the gcloud SDK on your computer.
Authenticate yourselves with the command gcloud auth login or gcloud init (proposed at the end of the installation)
Generate an access token gcloud auth print-access-token and copy it
Tips: you can skip the 2 first steps if you use Cloud Shell
Add the access token to the header to your Postman request like this:
Key is "Authrorization"
Value is "Bearer "
The access token is valid 1H, then you have to generate a new one.
(Not recommended) Make your model public (i.e. unauthenticated) like this (only in command line, it doesn't work on the GUI)
gcloud ai-platform models add-iam-policy-binding --member="allUsers" \
--role="roles/ml.modelOwner" <Model Name>
replace Model Name by your deployed model. However, it's only for test purpose. You have any filter and anyone can use it and you will pay for the processing incurs.

AWS Cognito; unauthorized_client error when hitting /oauth2/token

Steps taken so far:
Set up new user pool in cognito
Generate an app client with no secret; let's call its id user_pool_client_id
Under the user pool client settings for user_pool_client_id check the "Cognito User Pool" box, add https://localhost as a callback and sign out url, check "Authorization Code Grant", "Implicit Grant" and everything under "Allowed OAuth Scopes"
Create a domain name; let's call it user_pool_domain
Create a new user with a username/password
Now, I can successfully go to:
https://{{user_pool_domain}}.auth.us-east-2.amazoncognito.com/oauth2/authorize?response_type=code&client_id={{user_pool_client_id}}&redirect_uri=https%3A%2F%2Flocalhost
This presents me with a login page and I am able to login as my user which returns me to https://localhost/?code={{code_uuid}}
I then try the following:
curl -X POST https://{{user_pool_domain}}.auth.us-east-2.amazoncognito.com/oauth2/token -H 'Content-Type: application/x-www-form-urlencoded' -d 'grant_type=authorization_code&redirect_uri=https%3A%2F%2Flocalhost&code={{code_uuid}}&client_id={{user_pool_client_id}}'
However, this just returns back the following:
{"error":"unauthorized_client"}
The token endpoint docs say that unauthorized_client is because "Client is not allowed for code grant flow or for refreshing tokens." which is confusing because I checked the boxes allowing the client to use the code grant flow.
So, it turns out that the user pool has to have a trailing slash (https://localhost/) and then that trailing slash has to be used in all of the callback URLs. Then it decides to work!
Everything looks OK to me. I think it may be complaining about the Authorization header missing but not sure. You could try a few things:
1) According to this page (https://docs.aws.amazon.com/cognito/latest/developerguide/token-endpoint.html), you shouldn't need to send the Authorization header in the token request, but maybe it is still needed. You could try either passing just the client ID in it (Authorization [client ID]) or configure a secret and try passing Authorization [client ID:client secret] like it says). It usually makes sense to use a client secret for authorization code flow anyway since in this flow, there is a server side component that can securely handle the token exchange.
2) Try using Implicit Flow instead to see if that works. Implicit Flow makes sense for single page apps with no server side component. For that, no client secret is needed.
If you are using amplify and have it configured outside of the CLI and the other answers aren't working for you, one last fix you can try is to ensure you have responseType: 'token' if you are using implicit flow. Fixed things for me.
Auth: {
oauth: {
domain : 'your-app.auth.your-region.amazoncognito.com',
redirectSignIn: environment.cognito.oauthCallbackLogin,
redirectSignOut: environment.cognito.oauthCallbackLogout,
responseType: 'token',
scope : ['email', 'openid', 'profile'],
}
}
I had this error for another reason: I had response_type=token in the request URL, but the implicit OAuth flow was not enabled in the user pool client, so I needed to change it to response_type=code.
I agree with #rioastamal and #kiran01bm
as well. I did not need a trailing slash and it has to be verbatim as configured for the callbacks.
In my case I had my Redirect URI encoded at definition like this const redirectUri = encodeURIComponent(REDIRECT_URI).
Later, when it was used in the POST call to the /token endpoint as part of the params, it resulted as a double-encoded string.
A facepalm moment, but could happen to anyone.
Getting rid of one of the encoding fixed it for me.
Make sure to also include the scope in the request. Like the following
https://domain.auth.eu-central-1.amazoncognito.com/signup?client_id={}&response_type=token&scope=aws.cognito.signin.user.admin+email+openid+phone+profile&redirect_uri=https://www.google.com/
I my case, the issue came from the ACS URL that was incorrect, but so close that I did not see it. It was redirecting my to a page with this error "An error was encountered with the requested page."
I configured the UserPoolClient via cloudformation and had the AllowOAuthFlows set to implicit, where to work with amplify/cognito I needed that value to be code.
GoogleUserPoolClient:
Type: AWS::Cognito::UserPoolClient
DependsOn: GoogleUserPoolIdentityProvider
Properties:
UserPoolId:!Ref MyUserPool
AllowedOAuthFlowsUserPoolClient: true
GenerateSecret: false
CallbackURLs:
- http://localhost:8080
LogoutURLs:
- http://localhost:8080
AllowedOAuthFlows:
- code
AllowedOAuthScopes:
- email
- openid
SupportedIdentityProviders:
- Google
Authorization code grant means you get a code at the end of that redirect and you have to exchange that code for the respective tokens, and the response Type will be code.
And the Implicit grant type is the equivalent of response type token, where in you will get the tokens on the first step itself.
So check if you have the correct response type as per your auth flow set in the cognito console.
In my case, I updated the localhost:port in Allowed callback URLs of cognito app client setting but failed to add localhost:port to Allowed sign-out URLs

connecting to my app on kinvey using rest

I am trying to connect to my app on kinvey. From a browser, I can simply use:
https://baas.kinvey.com/appdata/<app_key>?app_secret=<secret>
I do get prompted to enter app_key and app_secret as uid and password but at least I get:
{
version: "3.8.13",
kinvey: "hello <my app name>",
appName: "<My app name>",
environmentName: "Development"
}
but, from python, I cannot. The closest I got was with:
requests.get('https://baas.kinvey.com/', headers={'app_key': app_key, 'app_secret': secret})
That takes me to a generic kinvey 'hello' but not to my app.
I also tried with
requests.get('https://baas.kinvey.com/' + app_key, headers={'app_key': app_key, 'app_secret': secret})
If i try to add the app_key + '?app_secret=' + secret to the url I get an error on malformed header/missing credentials.
Thoughts?
The correct way to add credentials to a Kinvey mbaas request is by setting a Basic Auth header, as explained here. Using the headers that you describe is not supported.
The steps here are that you use a base64-encoded appkey/appsecret to build a Basic Auth header in order to get to the "login" endpoints, after which you'll get a Kinvey token for the session authentication corresponding to the active user. There is no such thing as anonymous access to your app, apart from getting to the login endpoint.
Basically, this is not trivial. This is why using the REST API directly is not recommended, and using a specific SDK for your platform is. There's SDK's for many platforms including java/android, javascript, C#/xamarin, xcode/swift, etc. In those SDK's, you simply call functions like "Kinvey.login" or "Kinvey.appdata.get" and all auth and all offline, caching, etc. is taken care for you.