Using Postman to access OAuth 2.0 Google APIs - oauth-2.0

I am trying to access Proximity Google API using Postman chrome app. I have followed tutorials on postman and google dev website but I'm still getting 401 error message.
What am I doing?
Step 1 - Enable Proximity API:
In order to use Proximity API, it has to be first enabled in Google Dev console.
Using this tutorial I have enabled support for Proximity API for my project
Step 2 - Get the credentials:
According to this tutorial, I need to get client ID and secret. This is where I am confused. Credentials->Add credentials->OAuth2.0 client ID->select Chrome App radio button (since I am using Postman)->enter last part of Postman's Chrome Web store URL [which is fhbjgbiflinjbdggehcddcbncdddomop]->hit create button These steps will only generate a client ID, not a secret..am I doing something wrong?
From the Google Dev console, one can download an JSON file which has client id, auth URI and Token URI
I downloaded this but this is of little help if I am using Postman. I am guessing this JSON file is something that can be included in a JS application.
Step 3 - Use Postman to test the API
What am I getting?
And, once I click on the debug URL, I see the following screen

Postman will query Google API impersonating a Web Application
Generate an OAuth 2.0 token:
Ensure that the Google APIs are enabled
Create an OAuth 2.0 client ID
Go to Google Console -> API -> OAuth consent screen
Add getpostman.com to the Authorized domains. Click Save.
Go to Google Console -> API -> Credentials
Click 'Create credentials' -> OAuth client ID -> Web application
Name: 'getpostman'
Authorized redirect URIs: https://www.getpostman.com/oauth2/callback
Copy the generated Client ID and Client secret fields for later use
In Postman select Authorization tab and select "OAuth 2.0" type. Click 'Get New Access Token'
Fill the GET NEW ACCESS TOKEN form as following
Token Name: 'Google OAuth getpostman'
Grant Type: 'Authorization Code'
Callback URL: https://www.getpostman.com/oauth2/callback
Auth URL: https://accounts.google.com/o/oauth2/auth
Access Token URL: https://accounts.google.com/o/oauth2/token
Client ID: Client ID generated in the step 2 (e.g., '123456789012-abracadabra1234546789blablabla12.apps.googleusercontent.com')
Client Secret: Client secret generated in the step 2 (e.g., 'ABRACADABRAus1ZMGHvq9R-L')
Scope: see the Google docs for the required OAuth scope (e.g., https://www.googleapis.com/auth/cloud-platform)
State: Empty
Client Authentication: "Send as Basic Auth header"
Click 'Request Token' and 'Use Token'
Set the method, parameters, and body of your request according to the Google docs

The best way I found so far is to go to the Oauth playground here: https://developers.google.com/oauthplayground/
Select the relevant google api category, and then select the scope inside that category in the UI.
Get the authorization code by clicking "authorize API" blue button.
Exchange authorization code for token by clicking the blue button.
Store the OAuth2 token and use it as shown below.
In the HTTP header for the REST API request, add: "Authorization: Bearer ". Here, Authorization is the key, and "Bearer ". For example: "Authorization: Bearer za29.KluqA3vRtZChWfJDabcdefghijklmnopqrstuvwxyz6nAZ0y6ElzDT3yH3MT5"

The current answer is outdated. Here's the up-to-date flow:
The approach outlined here still works (28th of july 2022, confirmed by Jordy)
We will use the YouTube Data API for our example. Make changes accordingly.
Make sure you have enabled your desired API for your project.
Create the OAuth 2.0 Client
Visit https://console.cloud.google.com/apis/credentials
Click on CREATE CREDENTIALS
Select OAuth client ID
For Application Type choose Web Application
Add a name
Add following URI for Authorized redirect URIs
https://oauth.pstmn.io/v1/callback
Click Save
Click on the OAuth client you just generated
In the Topbar click on DOWNLOAD JSON and save the file somewhere on your machine.
We will use the file later to authenticate Postman.
Authorize Postman via OAuth 2.0 Client
In the Auth tab under TYPE choose OAuth 2.0
For values under Configuration Options enter the values found inside the client_secret_[YourClientID].json file we downloaded in step 9
Click on Get New Access Token
Make sure your settings are as follows:
Click here to see the settings
(In addition, multiple scope can be as follows, space-delimited: "https://www.googleapis.com/auth/userinfo.email https://www.googleapis.com/auth/userinfo.profile")
Click on Request Token
A new browser tab/window will open
Once the browser tab opens, login via the appropriate Google account
Accept the consent screen
Done
Ignore the browser message "Not safe" etc. This will be shown until your app has been screened by Google officials. In this case it will always be shown since Postman is the app.

go to https://console.developers.google.com/apis/credentials
create web application credentials.
Postman API Access
use these settings with oauth2 in Postman:
Auth URL = https://accounts.google.com/o/oauth2/auth
Access Token URL = https://accounts.google.com/o/oauth2/token
Choose Scope for the HTTP API
Generate Token
to add Schema use:
SCOPE = https: //www.googleapis.com/auth/admin.directory.userschema
post https: //www.googleapis.com/admin/directory/v1/customer/customer-id/schemas
{
"fields": [
{
"fieldName": "role",
"fieldType": "STRING",
"multiValued": true,
"readAccessType": "ADMINS_AND_SELF"
}
],
"schemaName": "SAML"
}
to patch user use:
SCOPE = https://www.googleapis.com/auth/admin.directory.user
PATCH https://www.googleapis.com/admin/directory/v1/users/admin#email.com
{
"customSchemas": {
"SAML": {
"role": [
{
"value": "arn:aws:iam::123456789123:role/Admin,arn:aws:iam::123456789123:saml-provider/GoogleApps",
"customType": "Admin"
}
]
}
}
}

I figured out that I was not generating Credentials for the right app type.
If you're using Postman to test Google oAuth 2 APIs, select
Credentials -> Add credentials -> OAuth2.0 client ID -> Web Application.

This is an old question, but it has no chosen answer, and I just solved this problem myself. Here's my solution:
Make sure you are set up to work with your Google API in the first place. See Google's list of prerequisites. I was working with Google My Business, so I also went through it's Get Started process.
In the OAuth 2.0 playground, Step 1 requires you to select which API you want to authenticate. Select or input as applicable for your case (in my case for Google My Business, I had to input https://www.googleapis.com/auth/plus.business.manage into the "Input your own scopes" input field). Note: this is the same as what's described in step 6 of the "Make a simple HTTP request" section of the Get Started guide.
Assuming successful authentication, you should get an "Access token" returned in the "Step 1's result" step in the OAuth playground. Copy this token to your clipboard.
Open Postman and open whichever collection you want as necessary.
In Postman, make sure "GET" is selected as the request type, and click on the "Authorization" tab below the request type drop-down.
In the Authorization "TYPE" dropdown menu, select "Bearer Token"
Paste your previously copied "Access Token" which you copied from the OAuth playground into the "Token" field which displays in Postman.
Almost there! To test if things work, put https://mybusiness.googleapis.com/v4/accounts/ into the main URL input bar in Postman and click the send button. You should get a JSON list of accounts back in the response that looks something like the following:
{
"accounts": [
{
"name": "accounts/REDACTED",
"accountName": "REDACTED",
"type": "PERSONAL",
"state": {
"status": "UNVERIFIED"
}
},
{
"name": "accounts/REDACTED",
"accountName": "REDACTED",
"type": "LOCATION_GROUP",
"role": "OWNER",
"state": {
"status": "UNVERIFIED"
},
"permissionLevel": "OWNER_LEVEL"
}
]
}

Google has changed the Access Token URL: https://accounts.google.com/o/oauth2/token.
It now needs to be: https://oauth2.googleapis.com/token

As an addition to the top answer by #DimaTx, don't forget to put checkmark on the "authorize using browser" tickbox, as explained by team postman themselves in github.com/postmanlabs/postman-app-support/issues/7700
This will prevent/solve the “This browser or app may not be secure” result.

Related

Not able to hit Twitter API through POSTMAN

I was trying to hit Twitter API to retrieve data from POSTMAN but I am stuck at an error.
I have created a project in Twitter and then created an app which is associated with the twitter project. Retrieved the Key, Secret and Bearer Token. I hit the below endpoint with Bearer token and got the error
endpoint : https://api.twitter.com/2/tweets?ids=1261326399320715264,1278347468690915330
Error: When authenticating requests to the Twitter API v2 endpoints, you must use keys and tokens from a Twitter developer App that is attached to a Project. You can create a project via the developer portal.
Then I hot the same endpoint using OAuth 1.0 with Consumer Key, Consumer Secret, Access Token and Access Secret and getting the below error
{
"title": "Unauthorized",
"type": "about:blank",
"status": 401,
"detail": "Unauthorized"
}
I do not understand what I am missing there. Can someone please help with this?
Edit by Espoir Murhabazi: I have tried to use beared token to authenticate as shown in this example but in vain
I tried to use the authentication scheme used by tweepy but also in vain. I look like there is something we are missing.
Here is a full example of what I have tried:
import requests
import os
import sys
from tweepy import OAuthHandler
from dotenv import load_dotenv
load_dotenv()
def get_twitter_auth():
"""Setup Twitter authentication.
Return: tweepy.OAuthHandler object
"""
try:
consumer_key = os.getenv('TWITTER_CONSUMER_KEY')
consumer_secret = os.getenv('TWITTER_CONSUMER_SECRET')
access_token = os.getenv('TWITTER_ACCESS_TOKEN')
access_secret = os.getenv('TWITTER_ACCESS_SECRET')
assert all([consumer_key, access_secret, access_token, consumer_secret])
except KeyError:
sys.stderr.write("TWITTER_* not found\n")
sys.exit(1)
auth = OAuthHandler(consumer_key, consumer_secret)
auth.set_access_token(access_token, access_secret)
return auth.apply_auth()
protected_url = "https://ads-api.twitter.com/9/insights/keywords/search?granularity=HOUR&keywords=developers&start_time=2021-07-02T10:00:00Z"
oauth = get_twitter_auth()
response = requests.get(url=protected_url, auth=oauth)
print(response.content, 10 * "**=|")
Thanks
Add your bearer token(received from twitter developer account) in the Authorization tab of postman[see attached image] and then request. I was able to get response for endpoint you mention.
Goto :
https://developer.twitter.com/en/portal/projects/new
Create a new app , and copy the bearer token that will be generated
and in postman use :
output:
First make sure you are using GET request instead of the other request type for this specific request (as shown in their docs here with a Postman example. I just tried to use POST and I got the same error, but works fine on GET request. This is the result I get with the URL in the question copied and pasted without any edits; and using GET request with Bearer Token as my authentication:
{
"data": [
{
"id": "1261326399320715264",
"text": "Tune in to the #MongoDB #Twitch stream featuring our very own #suhemparack to learn about Twitter Developer Labs - starting now! https://twitter.com/MongoDB/status/1261091720801980419"
},
{
"id": "1278347468690915330",
"text": "Good news and bad news: \n\n2020 is half over"
}
]
}
url in the above snippet was edited and replaced with the full URL as StackOverflow doesn't accept shortened URLs.
To change the request type do the following:
Open Postman
Click on the select input (also called combo box) on the left side of the URL input textbox (where you wrote the URL https://api.twitter.com/2/tweets?ids=1261326399320715264,1278347468690915330). Shouldn't be hard to see.
Select GET on the options. If that doesn't work then it's time to reset your keys.
To reset your keys (called regenerating according to Twitter) do the following (you may skip this whole process if the above solved your issue):
go to your project in your Twitter developer account.
In the main view for your project you should see your apps with two icons; a gear and key icon. Look for the app you want to edit, click on the key icon next to it
On the next page you can regenerate any of the keys you might have lost access to. If you choose to regenerate the Bearer Token, click on regenerate on the same line with the Bearer Token text.
You can now copy the Bearer Token to your clipboard, I recommend copying it to somewhere safe so you don't have to keep resetting.
After copying the Bearer Token, open postman
Duplicate the tab with the GET request
Under the URL textbox there should be a tab written Authorisation. Click on it.
Under that tab there should be a select input (combobox) with the label type, click on it and select Bearer Token.
On the right there will appear an input with the label token on its left side. Go to that input and paste your URL, use the same exact one you used in the question as it works as is.
For the final step, press Enter or go to the button written Send on the right side of the URL textbox. If everything was done correctly you should have your results.
Bearer Tokens are the predominant type of access token used with OAuth 2.0. A Bearer Token is an opaque string, not intended to have any meaning to clients using it. Instead of using a bearer token try with the access_token and access_token_secret. For more info refer this

Authenticate Azure API Management with OAuth2 using Azure AD

I am trying to secure APIM APIs using OAuth2 via AzureAD by reading the article: Protect a web API backend in Azure API Management by using OAuth 2.0 authorization with Azure AD
AzureAPIM - OAuth2
Authorization endpoint URL (v1): https://login.microsoftonline.com/{tenant}/oauth2/authorize
Token endpoint URL (v1): https://login.microsoftonline.com/{tenant}/oauth2/token
Client ID: client-app id
Redirect URI: (deprecated portal): https://xxx-api.portal.azure-api.net/docs/services/auth1/console/oauth2/authorizationcode/callback
AzureAD - backend-app:
scope: Files.All
AzureAD - client-app:
secret key: xxx
Redirect url: ONLY WORK with deprecated portal in APIM (https://xxx-api.portal.azure-api.net/docs/services/auth1/console/oauth2/authorizationcode/callback)
For Demo Conference API, Add Validate JWT policy to Inbound processing where 3a0cf09b- is tenant id and b7c31179- is backend-app application id:
In Developer portal, the authentication to AzureAD is successful with a return token:
However the authorization is failed with calling the API:
Inspecting the received token in jwt.io, I found that the "aud": "00000003-0000-0000-c000-000000000000" is not backend-app application id:
{
"aud": "00000003-0000-0000-c000-000000000000",
"iss": "https://sts.windows.net/3a0cf09b-xxx/",
"app_displayname": "client-app",
"appid": "05a245fb-xxx",
"scp": "Files.Read User.Read profile openid email",
"tenant_region_scope": "OC",
"tid": "3a0cf09b-2952-4673-9ace-0e1bf69ee23a",
"unique_name": "user1#xxx.onmicrosoft.com",
}
API Test HTTP response trace shows the error on validate-jwt:
validate-jwt (-0.138 ms)
{
"message": "JWT Validation Failed: Claim value mismatch: aud=b7c31179-xxx.."
}
Replacing aud by the value in the token 00000003-0000-0000-c000-000000000000 or removing the required-claims in the validate-jwt policy to get it working.
Any idea please?
From your error report, it is indeed a 401 error, that is, your aud does not match the api you want to call, I use the auth code flow to do a simple demonstration for you:
First expose the api of the back-end application and add the client application.
Next,under 'API permissions', give your front-end application access to your backend api:
Under 'API permissions' click on 'Add permission', then click on the 'My APIs' tab.
Find your backend application and select the appropriate scope.
Click 'Add permissions'.
Grant admin consent for your APIs.
Get token:
Parse the token:
It seems you choose v1 endpoint of OAuth2 authorization but not v2 endpoint, so the value of aud in access token should be like b7c31179-xxxx.... but not api://b7c31179-xxxx..... So there are no mistakes in your steps of get access token.
According to some test in my side, the cause of this problem is you did not specify a parameter resource with the value of the backend-app application id when you configure OAuth2.0 in your APIM. The document you refer to also mentions this (I test with not specify this parameter, it shows same problem with yours)
So to solve this problem, please go to your APIM and click "OAuth 2.0" tab, edit the item you created. Add a parameter resource with value of the backend-app application id.
Note: When you add the parameter resource and click "Save" button, please open the item again and check if the "Client secret" box is empty. When I test in my side, the "Client secret" box shows empty after add parameter resource, it may be a bug on that page. If "Client secret" is empty, it might show error message like The request body must contain the following parameter: 'client_assertion' or 'client_secret' when you get the access token in Developer portal.

Actions on Google and Account linking failure after tokens returned

Trying to test auth in the Web Simulator using the OAuth2 Authorization Code Flow, https://developers.google.com/actions/tools/web-simulator
See: https://developers.google.com/actions/tools/testing#testing_account_linking_with_google_home_web_simulator
And:
https://developers.google.com/actions/develop/identity/oauth2-code-flow
Provided you've setup your Action to require authorization against your authorization service, when you try to access your Action the Assistant advises you that you need to Link your account.
In the same response the simulator provides a URL for initiating the linking process, see:
"debugInfo": {
"sharedDebugInfo": [
{
"name": "Account Linking Url",
"debugInfo": "https://assistant.google.com/services/auth/handoffs/auth/start?provider=your-google-project-id_dev&scopes=your-scopes&return_url=https://www.google.com/"
}
]
}
Calling this URL (paste into a browser) will take you through an OAuth2 flow, assuming the user actions required are successful Google will call your token endpoint with the authorization code provided during the flow.
But then I was getting:
result_code=FAILURE&result_message=Account+linking+failed
It all appeared to be working from my side but Google was returning a FAILURE.
In my case, my token endpoint was returning my standard token response object, which included an access_token, a refresh_token, an expires_in, a session_state and another token that wasn't needed for this purpose but was standard to my token response.
And when I tested this same response on Googles playground it was fine:
https://developers.google.com/oauthplayground/
But not so when using the Assistant URL:
https://assistant.google.com/services/auth/handoffs/auth/start?provider=your-google-project-id_dev&scopes=your-scopes&return_url=https://www.google.com/
The reason it turns out is that the Assistant does not like superfluous properties in the response object.
I have yet to fully establish what is and isn't allowed but so far you can have:
{
"token_type": "Bearer",
"access_token: "xxx",
"refresh_token": "yyy",
"expires_in": "zzz"
}
With these I now get:
result_code=SUCCESS

How do I Implement twitter Oauth into my Google chrome extension

I figured out how to get the sign in button and redirect through php code. BUT, Chrome Dev only allows client side code. How do I get the log in with twitter with client side code for my Chrome app?
is there a way to run php code for a chrome app?
Here is another alternative to CodeBird for authenticating a twitter user in a Chrome extension.
The key with this approach is to provide Twitter with a legitimate domain for the callback URL for your app. Then, use content scripts to inject a script onto that same domain. That script will parse the query string of the URL to get the tokens and send those tokens in a message to your extension's background script. Your background script will take the tokens and then perform the third leg of the oauth process, which will finally get you the oauth token and oauth token secret.
Here is a brief example:
in your manifest.json, make sure your content script matches the same domain that you put in your twitter app settings callback URL:
"content_scripts": [{
"matches": ["https://andyjiang.com/*"],
"js": ["js/session.js"]
}]
Then, in your js/session.js file, have this sort of logic:
chrome.runtime.sendMessage({type: 'auth', session:
window.location.search.substr(1)}, function(response) {
window.open('', '_self', '');
window.close();
});
In your background script, have some logic that listens for the message, gets the token, and uses Twitter's API for the third leg of the oauth process to finally get the oauth token and oauth token secret, which you can then save in localStorage or chrome.storage.
Here is sample code of the logic:
https://github.com/lambtron/chrome-extension-twitter-oauth-example
Hope that helps!
You can use the Chrome Identity API for this. Check out Non-Google account authentication for simple instructions on making a request using the launchWebAuthFlow API function.
Previously, there were client side libraries for implementing the OAuth flow, such as oauth2-extensions described here, but thankfully this is not required anymore .
Update
I've been playing around trying to get an example working for Twitter, but haven't quite got there. It appears that Twitter doesn't have an API endpoint that matches the OAuth2 URL that is expected. I think in the case of Twitter, you may have to use OAuth 1.0a instead, which would require a library after all. I found one called CodeBird. I will try and investigate further though.
Example using Chrome Identity API to Authorise Instagram
You need to register the client to your provider with https://abcdefghijklmnopqrstuvwxyzabcdef.chromiumapp.org/intagram_cb, where 'abcdefghijklmnopqrstuvwxyzabcdef' is replaced with your extension ID and intagram_cb is name for a path to be able to distinguish between other providers you wish to authenticate with within the extension. If you only have one, then you can omit it.
Add provider to the permissions property in the manifest.json file:
"permissions": [
"*://*.instagram.com/*"
]
Get access token. You obtain the client_id token from your provider account:
var redirect_uri = chrome.identity.getRedirectURL("intagram_cb");
var client_id = "123456789012345";
var auth_url = "https://instagram.com/oauth/authorize/?" +
"client_id=" + client_id + "&" +
"response_type=token&" +
"redirect_uri=" + encodeURIComponent(redirect_uri);
chrome.identity.launchWebAuthFlow({'url':auth_url, 'interactive': true},
function(redirect_url) {
// extract the token from this url and use it for future requests
var accessToken = redirect_url.substring(redirect_url.indexOf("=") + 1);
}
});

How to access another user's data via the Graph API?

Using the Graph API and related authentication/authorization flows, how can I access data of all users in an organization? Also, multiple organizations/tenants need to be able to use the app.
As an example: I have an app which needs to read events from all calendars of all users under contoso.onmicrosoft.com. I would like that jack#contoso.onmicrosoft.com, the administrator, authorizes the app which will then be able to read the mentioned the data. Using the Managed API this can be easily done via impersonation.
However, I am trying to do the same with Graph API and OAuth, but I can't find a straight forward solution, or I must be missing something very obvious. I have created an app through manage.windowsazure.com (multi-tenant), and configured it so that it requires Microsoft Graph API (all application and delegated permissions).
I did the following:
1) Point jack#contoso.onmicrosoft.com towards https://login.microsoftonline.com/common/oauth2/authorize?response_type=code&redirect_uri=<my redirect url>&client_id=<my client id>
2) Jack authorizes the app
3) I get back: <my redirect url>/?code=<my authorization code>&session_state=<blah>
4) I send a POST request like below:
POST https://login.microsoftonline.com/common/oauth2/token
Headers: content-type: application/x-www-form-urlencoded
Body:
grant_type=authorization_code&code=<my auth code from step above>
&redirect_uri=<my redirect url>
&client_id=<my client id>
&client_secret=<my client secret>
&resource=https%3A%2F%2Fgraph.microsoft.com%2F
5) When I do the following:
GET https://graph.microsoft.com/v1.0/users/jack#contoso.onmicrosoft.com/messages
Headers: Authorization: Bearer <auth token from step #4>
I get a 200 OK response with the messages.
When I do the following:
GET https://graph.microsoft.com/v1.0/users/anyotheruser#contoso.onmicrosoft.com/messages
Headers: Authorization: Bearer <auth token from step #4>
I get a 403 Forbidden response with:
{
"error": {
"code": "ErrorAccessDenied",
"innerError": {
"date": "2016-06-07T08:47:27",
"request-id": "5b629e30-e6bd-474d-b3dd-8ce25c5ad1c4"
},
"message": "Access is denied. Check credentials and try again."
}
}
The flow/URLs you've referenced are for the authorization code flow which leverages delegated scopes.
A) If you want the app to only work (i.e. access all calendars) for admins then you are using the right flow.
B) If you want the app to work for all users after the admin consents to it, you'll need to use the app (client credentials) flow and use application scopes. This means that you'll need to separate out consent from the regular auth flow.
For consent you'll need to to point the admin to the following url:
GET https://login.microsoftonline.com/common/oauth2/authorize?resource=https://graph.microsoft.com/&client_id=<YourClientId>&client_secret=<YourClientSecret>&response_type=code&redirectUri=<YourRedirectUri>&prompt=admin_consent
For auth flow you'll need a single call from your web server:
POST https://login.microsoftonline.com/common/oauth2/token
body resource=https://graph.microsoft.com/&client_id=<YourClientId>&client_secret=<YourClientSecret>&response_type=code
Or better yet, just use ADAL's AquireToken(resource, clientCredentials) overload.
Once that's done, your app should be good to go to make requests to Graph.
Regardless if you want to stick to A) or switch over to B), to double check that things are set up correctly you can:
Check the token that you get back from Graph (the one you attach to the request along with Bearer) and confirm that it has a roles entry with the roles you need i.e. Calendars.Read
NOTE: The following steps 2.a & 2.b require you to have admin to a test tenant where you'd be consenting to the application.
2.a Use GraphExplorer (https://graphexplorer2.azurewebsites.net/) and confirm that consent has been properly set up by querying
beta/servicePrincipals?$filter=displayName eq '[YourApplicationName]'
If nothing shows up, then the no one has consented to the application.
2.b (only applicable for auth code flow with delegated scopes) Use GraphExplorer and confirm that either delegation has been authorized correctly by querying
beta/oauth2permissiongrants?$filter=clientId eq '[IdFrom ServicePrincipal in 2.a]'
And ensuring you get either a result for the specific user in question or for "AllPrincipals".
More info on app vs delegated scopes here: http://graph.microsoft.io/en-us/docs/authorization/permission_scopes
More info on app flow here: https://graph.microsoft.io/en-us/docs/authorization/app_only
Please use the app-only auth flow (see https://graph.microsoft.io/en-us/docs/authorization/app_only) to use the application permissions - for the token request (step 4) you need to pass grant_type=client_credentials instead of grant_type=authorization_code.

Resources