LinkedIn API :: how to obtain the bearer access token - rest
It's not easy to use the official LinkedIn API and I cannot find a valid documentation.
Following the official documentation I created a new application in order to obtain the Client ID and Client Secret
When I now make a POST call through Postman to https://www.linkedin.com/oauth/v2/accessToken this is what I obtain:
{
"error": "invalid_grant_type",
"error_description": "The passed in grant_type is invalid"
}
Where am I wrong?
EDIT AFTER HELP FROM #Amit Singh
Thanks to #AmitSingh I was able to create 2 different applications, the test with the Client Credentials flow gave me as a result an error retrieving the token:
{
"error": "access_denied",
"error_description": "This application is not allowed to create application tokens"
}
When I try to use the LinkedIn 3-legged workflow I receive Unauthorized
EDIT 3: GETTING THERE THROUGH POSTMAN
I now see that I can ask Postman to do the job, however when I press on Get New Access Token it opens an error page. I believe the error might be in these 4 elements:
Token name: maybe I have to give a special token name?
Auth URL: I set https://www.getpostman.com/oauth2/callback as explained here but maybe I have to set something else?
Access Token URL: I left it blank, maybe I have to put something here?
State: I set a random string like Hello123Boy but maybe I have to put something else. Maybe is too long. Maybe is too short. Maybe it has to contain symbols, etc... ?
...Also, in the guide you linked it says that the applicatoin needs to have:
r_liteprofile
rw_company_admin
w_member_social
mine has nothing:
Being recently created is still under review. It says it can take up to 90 days. Is that true?
4th EDIT: I WANT TO BELIEVE!
Here we are, at least now I'm getting the error: Bummer, something went wrong. The redirect_uri does not match the registered value. This is amazing: finally an error that says where the problem is!
On the app the, on the Products tab, I choose Sign In with LinkedIn. As
Authorized redirect URLs for your app I set https://www.getpostman.com/oauth2/callback
In Postman I setup Auth URL and Access Token URL as you said:
LinkedIn Credential workflows
LinkedIn offers 2 different credential workflows.
LinkedIn 3-legged workflow - When you want to use an API that will access LinkedIn member's data. Authorization Code grant type needed.
LinkedIn Client Credentials flow - When you want to use an API that will access non-member resources. Client credentials grant needed.
What are grant types?
"Grant type" refers to how you have acquired an access token in an OAuth workflow.
Several grant types are supported. Some of them are:
Client Credentials - Used when you want to access your own resources and not any other users
Authorization Code - Used when an app wants to access a client's data
Refresh token - Exchange an expired access token for a valid access token, used to avoid repeated user involvement
Password - Used when there is high trust between the app and the user e.g. LinkedIn mobile app, you provide your username and password
Client Credentials flow
What you need to know
Grant type used here is Client credentials - client_credentials.
Remember to set your Content-Type to application/x-www-form-urlencoded for all POST requests in OAuth.
Steps
Create an App and get your Client ID and Client Secret. Steps are shown in the respective docs linked above. Let's say they have values - <client_id> and <client_secret>.
Send a POST required to https://www.linkedin.com/oauth/v2/accessToken with following information.
Parameters
grant_type : client_credentials
client_id : <client_id>
client_secret : <client_secret>
NOTE : client_credentials is the literal text to be entered for grant_type.
Response will return a JSON Object containing your access token and its expiry duration in seconds.
Response
{
"access_token" : <access_token>,
"expires_in" : "1800"
}
Use the <access_token> obtained in Step 2 make API requests.
Example
Request URL: https://www.linkedin.com/v2/jobs
Request type: GET
Parameters
Authorization: Bearer <access_token>
LinkedIn 3-legged workflow
What you need to know
Grant type will be Authorization code - code, since you want to access a user's data.
Your Content-Type should be application/x-www-form-urlencoded for all POST requests in OAuth.
Redirect URLs are URLs where you OAuth server will redirect the user after successful authorization.
These are verified against your provided redirect URLs to ensure that it's not fraudulent.
These should be absolute URLs.
URL arguments are ignored and cannot include a #.
Steps
Create app and provide the Redirect URLs, if not already provided. Check docs for information regarding how to do this.
Get your Client ID and Client Secret. Let's say the values are <client_id> and <client_secret>.
Generate a random, hard to guess string. Let's say it's <random-string>.
Choose one of the redirect URLs provided in Step 1, where you want user to be redirected after authorization. Let's say it is <redirect_uri>.
Let's suppose you want to:
r_emailaddress - Get his email address
w_member_social - Post, comment and like posts on behalf of the user.
These are referred as "permission scopes", as in what permissions is the user authenticating you for. When sending these scopes in your request, they should be URL-encoded and space-delimited. In this particular instance, our scope will be scope: r_emailaddress%20w_member_social. We have URL-encoded the scopes mentioned above.
Adding more information regarding scopes from the Microsoft docs:
The scopes available to your app depend on which Products or Partner Programs your app has access to. Your app's Auth tab will show current scopes available. You can apply for new Products under the Products tab. If approved, your app will have access to new scopes.
Send a POST request to https://www.linkedin.com/oauth/v2/authorization with following information.
Parameters
response_type : code
client_id : <client_id>
redirect_uri : <redirect_uri>
state : <random_string>
scope : r_emailaddress%20w_member_social
After the request, the user will be presented with LinkedIn's Auth screen and asked to approve the request.
After user approves the request and the <redirect_uri> has been verified, user will be redirected to provided <redirect_uri> along with the access code <access_code> and a value in state argument. Let's say in the state argument is <state_value>.
Verify that the <state_value> is equal to the <random_string> before working with the <access_code> to get access token, for security purposes. Also, use the <access_code> within 30 minutes of being issued, for security reasons.
Next, send a POST request to https://www.linkedin.com/oauth/v2/accessToken with following information to get the access token.
Parameters
grant_type : authorization_code
client_id : <client_id>
client_secret : <client_secret>
redirect_uri : <redirect_uri>
code : <access_code>
NOTE : authorization_code is the literal text to be passed in grant_type.
You should get a similar response as in the Client Credentials workflow containing your access token and expiry duration.
Response
{
"access_token" : <access_token>,
"expires_in" : "1800"
}
Use the <access_token> obtained in Step 9 make API requests.
Example
Request URL: `https://www.linkedin.com/v2/me`
Request type: GET
Parameters:
Authorization: Bearer <access_token>
How to do this in Postman?
Create a new Collection.
Right click, select edit collection and move to authorization tab.
In "Type", select "OAuth2.0", click on "Get New Access Token".
You will see a screen where all the familiar terms mentioned above are there. Fill those, check the "Authorize via Browser" checkbox for authorization.
Now you have the access token and can proceed to make your API calls.
Postman has been designed to make such operations easier, but you have to know how to do it. For more details, you can read their official docs.
Thanks to #timur and #AmitSingh I finally arrived to authenticate to LinkedIn API.
A brief step by step solution in pictures:
Authorized redirect URLs for your app = https://oauth.pstmn.io/v1/callback
OAuth 2.0 scopes = must have r_emailaddress and r_liteprofile
In the Products Tab set Sign In with LinkedIn
Now open Postman > Collections > New Collection > Authorization and set the parameters as in picture:
TYPE = OAUTH 2.0
Token Name = put whatever you want
Callback URL = https://oauth.pstmn.io/v1/callback (should be greyed out once you tick Authorize using browser)
Tick Authorize using browser
Auth URL = https://www.linkedin.com/oauth/v2/authorization
Access Token URL = https://www.linkedin.com/oauth/v2/accessToken
Client ID = The Client ID you find on your LinkedIn App
Client Secret = The Client Secret you find on your LinkedIn App
Scope = r_liteprofile r_emailaddress
State = put whatever you like
Now click on Get New Access Token, a page will open on your browser and you will be able to login using your LinkedIn account. Once done you are authenticated.
Now use the code provided by #timur and on Postman go to Import > Upload File and import that .JSON file. You will now have the 4 queries and you can drag and drop them in your collection.
Assuming you've created your app, added correct redirect URL and enabled "Sign In with LinkedIn" product for your app, the issue you are having is probably that the first call returns a login page where your users are supposed to authenticate.
submit the request to https://www.linkedin.com/oauth/v2/authorization (you seem to have done that)
parse response of step 1 and extract all form values, add username and password to simulate user login
make POST request and use values from previous step as x-www-form-urlencoded data
manually follow the redirect header from step 3
make note of second redirect header but do not follow it - instead extract the code
POST code from previous step to https://www.linkedin.com/oauth/v2/accessToken and get access_token in response
From here, I was able to successfully transition to the auth code by following the steps.
I am not sure if you use the online Postman, but here's my complete collection export file for reference:
{
"info": {
"_postman_id": "397761c9-4287-43f2-860a-3c34cb710d50",
"name": "Linkedin oAuth",
"schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json"
},
"item": [
{
"name": "01 request Login form",
"event": [
{
"listen": "test",
"script": {
"exec": [
"const $ = cheerio.load(pm.response.text());\r",
"var inputs = $('form').serializeArray();\r",
"var payload = '';\r",
"inputs.forEach(i => {\r",
" payload += encodeURIComponent(i.name)+ '=' + encodeURIComponent(i.value) + '&';\r",
"})\r",
"payload += 'session_key='+ encodeURIComponent(pm.collectionVariables.get('username')) + '&'\r",
"payload += 'session_password='+ encodeURIComponent(pm.collectionVariables.get('password'))\r",
"\r",
"pm.collectionVariables.set(\"form_data\", payload);"
],
"type": "text/javascript"
}
}
],
"request": {
"method": "GET",
"header": [],
"url": {
"raw": "https://www.linkedin.com/oauth/v2/authorization?response_type=code&client_id={{client_id}}&redirect_uri={{redirect_uri}}&scope=r_liteprofile&state={{$guid}}",
"protocol": "https",
"host": [
"www",
"linkedin",
"com"
],
"path": [
"oauth",
"v2",
"authorization"
],
"query": [
{
"key": "response_type",
"value": "code"
},
{
"key": "client_id",
"value": "{{client_id}}"
},
{
"key": "redirect_uri",
"value": "{{redirect_uri}}"
},
{
"key": "scope",
"value": "r_liteprofile"
},
{
"key": "state",
"value": "{{$guid}}"
}
]
}
},
"response": []
},
{
"name": "02 Submit login form",
"event": [
{
"listen": "prerequest",
"script": {
"exec": [
""
],
"type": "text/javascript"
}
},
{
"listen": "test",
"script": {
"exec": [
"var url = 'https://www.linkedin.com'+ pm.response.headers.get(\"Location\");\r",
"pm.collectionVariables.set('first_redirect', url);\r",
"//console.log(pm.collectionVariables.get('first_redirect'));"
],
"type": "text/javascript"
}
}
],
"protocolProfileBehavior": {
"followRedirects": false
},
"request": {
"method": "POST",
"header": [
{
"key": "Content-Type",
"value": "application/x-www-form-urlencoded",
"type": "text"
}
],
"body": {
"mode": "raw",
"raw": "{{form_data}}",
"options": {
"raw": {
"language": "text"
}
}
},
"url": {
"raw": "https://www.linkedin.com/checkpoint/lg/login-submit",
"protocol": "https",
"host": [
"www",
"linkedin",
"com"
],
"path": [
"checkpoint",
"lg",
"login-submit"
]
}
},
"response": []
},
{
"name": "03 handle login-success redirect",
"event": [
{
"listen": "test",
"script": {
"exec": [
"var sdk = require('postman-collection');\r",
"var redirect = new sdk.Url(pm.response.headers.get(\"Location\"));\r",
"pm.collectionVariables.set('code', redirect.query.filter(q => q.key === 'code').map(k => k.value)[0]);\r",
"//console.log(pm.collectionVariables.get('code'));"
],
"type": "text/javascript"
}
},
{
"listen": "prerequest",
"script": {
"exec": [
"console.log(pm.variables.get('first_redirect'));\r",
"pm.request.url.update(pm.variables.get('first_redirect'));"
],
"type": "text/javascript"
}
}
],
"protocolProfileBehavior": {
"followRedirects": false
},
"request": {
"method": "GET",
"header": [],
"url": {
"raw": "{{first_redirect}}",
"host": [
"{{first_redirect}}"
]
}
},
"response": []
},
{
"name": "04 Get Auth Code",
"request": {
"method": "POST",
"header": [],
"url": {
"raw": "https://www.linkedin.com/oauth/v2/accessToken?grant_type=authorization_code&code={{code}}&redirect_uri={{redirect_uri}}&client_id={{client_id}}&client_secret={{client_secret}}",
"protocol": "https",
"host": [
"www",
"linkedin",
"com"
],
"path": [
"oauth",
"v2",
"accessToken"
],
"query": [
{
"key": "grant_type",
"value": "authorization_code"
},
{
"key": "code",
"value": "{{code}}"
},
{
"key": "redirect_uri",
"value": "{{redirect_uri}}"
},
{
"key": "client_id",
"value": "{{client_id}}"
},
{
"key": "client_secret",
"value": "{{client_secret}}"
}
]
}
},
"response": []
}
],
"event": [
{
"listen": "prerequest",
"script": {
"type": "text/javascript",
"exec": [
""
]
}
},
{
"listen": "test",
"script": {
"type": "text/javascript",
"exec": [
""
]
}
}
],
"variable": [
{
"key": "client_id",
"value": "your app id"
},
{
"key": "client_secret",
"value": "your app secret"
},
{
"key": "redirect_uri",
"value": "your urlencoded redirect uri such as https%3A%2F%2Flocalhost%3A8080"
},
{
"key": "username",
"value": "user login"
},
{
"key": "password",
"value": "user password"
}
]
}
Related
How can I update a Keycloak password from the REST API (PUT method)?
I set up a keycloak server with LDAP users to take advantage of the SSO on my applications. I would like to change the password of the logged in user on my application through the Keycloak API. So, in the future, my Angular application will be able to make a request to the keycloak API to change the password of the logged-in user. So I tried to do what is indicated in the documentation (method PUT, reset-password) but without success ... I did my tests with postman, I wonder if my token is the one to be used? Does the problem come from elsewhere? I have this url : PUT {url}/auth/admin/realms/{realm}/users/{id user}/reset-password/ I have this header : Content-type application/json i have this body : { "pass" : { "type": "password", "temporary": false, "value": "my-new-password" } } I get a 401 error if I did not try to renew the token quickly (which makes me say that the problem may not come from the token) and I get a 403 or 400 error when I got a new token via postman oAuth 2.0 I sometimes get this message: Unrecognized field "pass" (class org.keycloak.representations.idm.CredentialRepresentation), not marked as ignorable Please, help me ! You can see here my autorization in postman, i don't know what is "State"
Body of PUT Should be CredentialRepresentation, which is { "type":"password", "value":"my-new-password", "temporary":false }
You can use POST method with these parametes: URL: http://[Server Address]/auth/admin/realms/[Realm Name]/users Headers: Content-Type application/json Body: { "username": "test", "firstName": "test", "lastName": "test", "email": "test#gmail.com", "enabled": true, "credentials": [{ "type": "password", "value": "123456", "temporary": false }] }
Change pass to credentials. it’s better to check current password to increase the security
Facebook Workplace Account Management API - Update user
I have a workplace application, I wish to change emailIds of the user via API, I found that Account Management API can be used to modify user details via API calls. My use-case is to modify user email via the Account Management API, which comes under urn:scim:schemas:core:1.0 schema extension, I wish to overwrite the existing email with the one I would specify in the requestBody, From the documentation, I've come up with the following request - Url endpoint - https://someCompanyName.facebook.com/scim/v1/Users/ HTTP/1.1 Method type - POST Request body- { "schemas": [ "urn:scim:schemas:core:1.0", "urn:scim:schemas:extension:facebook:auth_method:1.0" ], "userName": "abc", "name": { "formatted": "Julius Caesar" }, "emails": ["abc#gmail.com"], "urn:scim:schemas:extension:facebook:auth_method:1.0": { "auth_method": "password" } } Is it correct? What modifications do I need to make to the request?
in order to change the emails of a user you have to do a PUT request to the address https://www.facebook.com/scim/v1/Users/{userId} and you have to change in your payload the email address: { "schemas": [ "urn:scim:schemas:core:1.0", "urn:scim:schemas:extension:facebook:auth_method:1.0" ], "userName": "abc", "name": { "formatted": "Julius Caesar" }, "emails": [ { "primary": true, "type": "work", "value": "newemail#gmail.com" } ], "urn:scim:schemas:extension:facebook:auth_method:1.0": { "auth_method": "password" } } Hope it helps
admin Role within the loopback
I am having trouble setting up an admin Role within the loopback project with mongodb. I've set up a simple model, added acls, created a user and associated the user with the admin Role but I can't access the model through the API Explorer - it always comes back with "Authorization Required". Here are the steps I took: 1) I added model test through slc: slc loopback:model ? Enter the model name: test ? Select the data-source to attach test to: moti_db (mongodb) ? Select model's base class: PersistedModel ? Expose test via the REST API? Yes ? Custom plural form (used to build REST URL): Let's add some test properties now. Enter an empty property name when done. ? Property name: name ? Property type: string ? Required? No 2) create user through Sign Up page: id = 1 3) create admin Role through API: id = 1 4) changed Role and RoleMapping to public=true so I could set them through the rest api Here's the test data model: { "name": "test", "base": "PersistedModel", "idInjection": true, "properties": { "name": { "type": "string" } }, "validations": [], "relations": {}, "acls": [ { "accessType": "*", "principalType": "ROLE", "principalId": "$everyone", "permission": "DENY" }, { "accessType": "*", "principalType": "ROLE", "principalId": "admin", "permission": "ALLOW" } ], "methods": [] } Here's the Role { "id": 1, "name": "admin", "created": "2015-05-22T19:45:23.887Z", "modified": "2015-05-22T19:45:23.887Z" } Here's the RoleMapping: { "id": 1, "principalType": "USER", "principalId": "1", "roleId": 1 }
Did you set an Authorization Token at the top of the Explorer? You need to call User.login() with an email and password, then set the Auth Token to the returning auth ID value. Then this token is sent with all subsequent calls (as an authorization: header value and allows you to make calls that require auth. Another helpful thing is to run the API with ACL debugging, you can do DEBUG=loopback:security slc run and it will show you how it determines access. Maybe the output will be helpful (paste it here). Otherwise it's just a guess as your code looks good and assuming you've previously logged in and are using a token.
Retrieve comments on Facebook ads through the API
Is it even possible to retrieve comments on Facebook ads through the API (Graph or FQL)? If yes, do I need a whitelisted app to do it? Also, if I have a page access token, is it enough, or I need a user access token with ads_management permission?
Regarding the token usage, a page_token is extended by a given user to a given app. The page_token will have at most the same privileges as the user on his authorized pages and ad_accounts. Generating a page_token can be done automatically, in behalf of the user, if you already have a user_token with manage_pages permission. Again, this page_token will have at most the same privileges that the user_token you used to generate it. In other words, having a page_token doesn't amount for any additional privileges than the ones already present in the user_token. Having said that, you need a token with access to a given ad_account that the app for which that token was generated, has that ad_account active in its settings If the second requisite isn't met, for example for ad_account act_123456789 you'll get the error: { "error": { "message": "(#274) The ad account is not enabled for usage in Ads API. Please add it in developers.facebook.com/apps -> select your app -> settings -> advanced -> advertising accounts -> Ads API. Account 123456789 not enabled for this application.", "type": "OAuthException", "code": 274, "fbtrace_id": "xxxxx" } } You can try, for example, generating a token with all privileges for the Graph API Explorer App. It will throw the error above because said App doesn't have the ad_account act_123456789 enabled. So, given you have a token with ads_read extended for an app that has this ad_account listed, and you know the ad_id, you can procede as I explained in thread Get comments from facebook ads (marketing) Basically, you use the ad_id (for example 123000000) to get the promoted post id and its actions /123000000?fields=creative.fields(effective_object_story_id),insights.fields(actions) The answer will contain an effective_object_story_id (for example, let's say it is 456000000_789000000) and its actions broken down by type: { "creative": { "effective_object_story_id": "456000000_789000000", "id": "123000000" }, "insights": { "data": [ { "actions": [ { "action_type": "comment", "value": "12" }, { "action_type": "like", "value": "2" }, { "action_type": "post", "value": "3" }, { "action_type": "post_reaction", "value": "29" }, { "action_type": "video_view", "value": "558" }, { "action_type": "page_engagement", "value": "604" }, { "action_type": "post_engagement", "value": "602" } ], "date_start": "2017-08-14", "date_stop": "2017-08-20" } ], "paging": { "cursors": { "before": "xxx", "after": "xxx" } } } } If you want to also distinguish paid comments from regular comments, you can query the comments edge of the post_id 456000000_789000000 to get the overall comment count which should be greater than the comments generated by the ad.
You can't pull the actual words of the comment via the API - would make it too easy to scrape.
Yes, Facebook ads that have comments are because the ad is a promoted page post, whether that page post is hidden or not. Page post comments are available via the Facebook API and does not require having Ads API access. Use the graph API endpoint /v2.1/{page-id}/comments to retreive page post comments. See the Facebook Graph API documentation on object comments for more information.
FB Graph API: Way to get list of fields for an object through API
Is there a way how to get the list of fields for a specific facebook object programmatically? I know there's documentation for that, but I need some introspection - we're building a tool that would enable the user to select from existing fields. I mean something like: give me a list of fields for user, response: {"id", "name", "first_name", ...} Or some way how to get all the fields for one object and derive it from that?
Facebook enables you to pass metadata=1 parameter. For example cocacola?metadata=1 gives you all available connections and fields for the page: "metadata": { "connections": { "admins": "https://graph.facebook.com/cocacola/admins", "admin_settings": "https://graph.facebook.com/cocacola/admin_settings" }, "fields": [ { "name": "id", "description": "The Page's ID. No access token or user `access_token`. `string`." }, { "name": "name", "description": "The Page's name. No access token or user `access_token`. `string`." }, { "name": "link", "description": "Link to the page on Facebook. No access token or user `access_token`. `string` containing a valid URL." }, { "name": "category_lists", "description": "The Page's categories. No access token or user `access_token`. `string`." }, { "name": "is_published", "description": "Indicates whether the page is published and visible to non-admins. No access token or user `access_token`. `boolean`." } Looks like it's official, found it in the getting started manual