LinkedIn OAuth 2.0: From Authorization Code to Posting Shares
Learn how to implement LinkedIn’s OAuth 2.0 authorization code flow, exchange tokens, post a share, and handle pagination and rate limits in a server‑side app.
19 Oct 2025, 16:37 UTC

What You’ll Get
By the end of this article you will know how to:
- Register a LinkedIn app and obtain the client ID, client secret, and redirect URI.
- Launch the OAuth 2.0 authorization code flow from your server.
- Exchange the temporary authorization code for an access token and refresh token.
- Post a share to a user or organization using the
/v2/sharesendpoint. - Handle LinkedIn’s simple pagination pattern and respect rate limits.
- Recognize and avoid the most common mistakes that lead to 403 or 429 errors.
Step 1 – Register Your App
1. Log in to the LinkedIn Developer portal.
2. Create a new application. Note the Client ID and Client Secret.
3. In the Auth tab, add a Redirect URL that matches the endpoint on your server that will receive the authorization code. Example: https://yourapp.com/auth/linkedin/callback.
4. Under Products, enable Sign In with LinkedIn and Share on LinkedIn (or Organization Management if you plan to post on behalf of an org). Save changes.
Step 2 – Launch the Authorization Code Flow
Construct the authorization URL and redirect the user’s browser to it. The user logs in, consents, and LinkedIn redirects back to your redirect_uri with a code query parameter.
https://www.linkedin.com/oauth/v2/authorization?response_type=code
&client_id={client_id}
&redirect_uri={redirect_uri}
&scope=w_member_social%20r_liteprofile
&state=RANDOM_STRING
Replace {client_id} and {redirect_uri} with your app values. The scope must include w_member_social (personal posts) or w_organization_social (org posts). The state protects against CSRF; store it in the user’s session and verify it on callback.
Step 3 – Exchange Code for Tokens
On your server, receive the code from the query string and POST to LinkedIn’s token endpoint:
POST https://www.linkedin.com/oauth/v2/accessToken
Content-Type: application/x-www-form-urlencoded
grant_type=authorization_code
&code={authorization_code}
&redirect_uri={redirect_uri}
&client_id={client_id}
&client_secret={client_secret}
Expected JSON response:
{
"access_token": "AQX...",
"expires_in": 3600,
"refresh_token": "AQY..."
}
The access_token lasts ~60 minutes. Store the refresh_token securely on the server; it is long‑lived and can be used to obtain a new access token without user interaction.
Refreshing an Access Token
POST https://www.linkedin.com/oauth/v2/accessToken
Content-Type: application/x-www-form-urlencoded
grant_type=refresh_token
&refresh_token={refresh_token}
&client_id={client_id}
&client_secret={client_secret}
LinkedIn returns a new access_token and a new refresh_token. Replace the old values in your storage.
Step 4 – Post a Share
With a valid access token, you can POST to /v2/shares. The request must include the X-Restli-Protocol-Version: 2.0.0 header and the token in the Authorization header.
POST https://api.linkedin.com/v2/shares
Authorization: Bearer {access_token}
X-Restli-Protocol-Version: 2.0.0
Content-Type: application/json
{
"owner": "urn:li:person:{person_id}",
"text": {
"text": "Hello LinkedIn!"
}
}
Replace {person_id} with the LinkedIn ID of the user. If posting to an organization, use urn:li:organization:{org_id} and ensure the scope w_organization_social is granted.
On success, LinkedIn returns a JSON body containing the new share’s URN. Verify in the LinkedIn UI or by fetching the share with /v2/shares/{share_id}.
Step 5 – Handle Pagination
Many LinkedIn endpoints return a limited set of results. Include start and count query parameters. The response contains a paging object with total and links (next/prev).
GET https://api.linkedin.com/v2/people/(id=me)/following?start=0&count=10
Authorization: Bearer {access_token}
X-Restli-Protocol-Version: 2.0.0
Inspect the paging object:
{
"elements": [...],
"paging": {
"total": 123,
"start": 0,
"count": 10,
"links": [
{
"rel": "next",
"href": "/v2/people/(id=me)/following?start=10&count=10"
}
]
}
}
Use the next link or increment start by count until start + count >= total.
Common Pitfalls & Limits
- Wrong Scope: Posting fails with 403 if you omit
w_member_socialorw_organization_social. Verify the scopes in the token response. - Missing Header: Forgetting
X-Restli-Protocol-Version: 2.0.0results in 400 errors. Always include it. - Exposing Secrets: Never embed
{client_secret}or{refresh_token}in client‑side JavaScript. Store them on the server behind authentication. - Rate Limits: Each app has a per‑minute limit (currently 100 requests for most endpoints). Monitor the
X-RateLimit-Remainingheader; a 429 response means you must pause. - Token Expiry: Access tokens expire after ~60 minutes. If your user session is long, refresh the token periodically or before each API call.
- Redirect URI Mismatch: LinkedIn will reject the flow if the
redirect_uriin the token request differs from the one used in the authorization step. - Pagination Off‑By‑One: Remember that
startis zero‑based; the first page usesstart=0.
Practical Verification Checklist
- Register the app and note
client_idandclient_secret. - Run the authorization URL in a browser, consent, and capture the
codefrom the redirect. - Exchange the code for tokens; confirm you receive
access_tokenandrefresh_token. - POST a share; check the response and verify the post appears on LinkedIn.
- Make a paginated GET request; confirm the
pagingobject and iterate until all items are retrieved. - Observe the
X-RateLimit-Remainingheader on each response; ensure it never drops below 10 during normal operation. - Simulate token expiry by waiting 61 minutes, then attempt an API call; confirm you receive a 401 and refresh the token.
By following these steps and checking the listed items, you can reliably integrate LinkedIn’s API into a server‑side application while avoiding the most frequent errors.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.