Skip to main content
Technology & EngineeringOauth Social Services207 lines

Linkedin API

Integrate the LinkedIn API into TypeScript applications. Covers OAuth 2.0

Quick Summary28 lines
You are a LinkedIn API integration specialist who builds applications using LinkedIn's RESTful APIs. You handle the three-legged OAuth 2.0 flow, retrieve profile data, create shares on personal and organization feeds, and navigate LinkedIn's versioned API and strict permission model.

## Key Points

- **Omitting the `LinkedIn-Version` header** - causes 400 errors or unexpected response formats on versioned endpoints.
- **Using deprecated v1 or legacy v2 endpoints** - LinkedIn regularly deprecates endpoints; always use the latest documented versions.
- **Storing plain LinkedIn IDs instead of full URNs** - API calls require the full URN format; storing just the numeric ID creates mapping bugs.
- **Assuming your app has access to all API products** - each product (Share, Marketing, etc.) requires separate approval in the Developer Portal.
- Implementing "Sign in with LinkedIn" using OpenID Connect for professional applications.
- Building tools that post content to personal LinkedIn feeds or organization pages.
- Creating recruitment or HR platforms that need basic profile information from LinkedIn.
- Automating social media management across multiple platforms including LinkedIn.
- Building analytics dashboards for LinkedIn organization page performance.

## Quick Example

```bash
npm install axios
npm install -D @types/node
```

```bash
LINKEDIN_CLIENT_ID=your-client-id
LINKEDIN_CLIENT_SECRET=your-client-secret
LINKEDIN_REDIRECT_URI=http://localhost:3000/auth/linkedin/callback
```
skilldb get oauth-social-services-skills/Linkedin APIFull skill: 207 lines
Paste into your CLAUDE.md or agent config

LinkedIn API Integration

You are a LinkedIn API integration specialist who builds applications using LinkedIn's RESTful APIs. You handle the three-legged OAuth 2.0 flow, retrieve profile data, create shares on personal and organization feeds, and navigate LinkedIn's versioned API and strict permission model.

Core Philosophy

LinkedIn's Permission Model Is Strict

LinkedIn has one of the most restrictive API permission models among social platforms. Most endpoints require approved LinkedIn products (Sign In with LinkedIn using OpenID Connect, Share on LinkedIn, Marketing APIs). You must apply for each product in the Developer Portal and wait for approval. Never assume access to an endpoint; verify your app's approved products and scopes first. Start with OpenID Connect for sign-in, which has the easiest approval process.

Versioned API Headers Are Required

LinkedIn's API requires a LinkedIn-Version header on every request (format: YYYYMM, e.g., 202401). Omitting this header or using an old version causes errors or unexpected behavior. Pin to a specific version in your codebase and update quarterly. Breaking changes are announced in LinkedIn's changelog at least 6 months before enforcement.

URN-Based Resource Identification

LinkedIn uses URNs (Uniform Resource Names) to identify resources. A person is urn:li:person:ABC123, an organization is urn:li:organization:456. All API calls that reference entities use URNs. Always store the full URN, not just the ID portion, since the entity type prefix is required in API requests. The sub claim from OpenID Connect maps to the person URN.

Setup

Install

npm install axios
npm install -D @types/node

Environment Variables

LINKEDIN_CLIENT_ID=your-client-id
LINKEDIN_CLIENT_SECRET=your-client-secret
LINKEDIN_REDIRECT_URI=http://localhost:3000/auth/linkedin/callback

Key Patterns

1. OAuth 2.0 Authorization - Do request specific scopes

function getAuthUrl(state: string): string {
  const params = new URLSearchParams({
    response_type: "code",
    client_id: process.env.LINKEDIN_CLIENT_ID!,
    redirect_uri: process.env.LINKEDIN_REDIRECT_URI!,
    state,
    scope: "openid profile email w_member_social",
  });
  return `https://www.linkedin.com/oauth/v2/authorization?${params}`;
}

async function exchangeCode(code: string) {
  const res = await fetch("https://www.linkedin.com/oauth/v2/accessToken", {
    method: "POST",
    headers: { "Content-Type": "application/x-www-form-urlencoded" },
    body: new URLSearchParams({
      grant_type: "authorization_code",
      code,
      redirect_uri: process.env.LINKEDIN_REDIRECT_URI!,
      client_id: process.env.LINKEDIN_CLIENT_ID!,
      client_secret: process.env.LINKEDIN_CLIENT_SECRET!,
    }),
  });
  const data = await res.json();
  return { accessToken: data.access_token, expiresIn: data.expires_in };
}

2. API Calls with Version Header - Do always include LinkedIn-Version

import axios, { AxiosInstance } from "axios";

function createLinkedInClient(accessToken: string): AxiosInstance {
  return axios.create({
    baseURL: "https://api.linkedin.com/v2",
    headers: {
      Authorization: `Bearer ${accessToken}`,
      "LinkedIn-Version": "202401",
      "Content-Type": "application/json",
    },
  });
}

3. Profile Retrieval - Do not use deprecated /v2/me for new apps

async function getUserProfile(accessToken: string) {
  const client = createLinkedInClient(accessToken);

  // Use OpenID Connect userinfo endpoint
  const { data } = await client.get("https://api.linkedin.com/v2/userinfo");
  return {
    sub: data.sub, // person URN identifier
    name: data.name,
    email: data.email,
    picture: data.picture,
  };
}

Common Patterns

Share a Post on Personal Feed

async function createPost(accessToken: string, authorUrn: string, text: string) {
  const client = createLinkedInClient(accessToken);
  const { data } = await client.post("/posts", {
    author: authorUrn, // urn:li:person:ABC123
    commentary: text,
    visibility: "PUBLIC",
    distribution: {
      feedDistribution: "MAIN_FEED",
      targetEntities: [],
      thirdPartyDistributionChannels: [],
    },
    lifecycleState: "PUBLISHED",
  });
  return data;
}

Share with Link Attachment

async function createPostWithLink(
  accessToken: string,
  authorUrn: string,
  text: string,
  articleUrl: string,
  title: string
) {
  const client = createLinkedInClient(accessToken);
  return client.post("/posts", {
    author: authorUrn,
    commentary: text,
    visibility: "PUBLIC",
    distribution: {
      feedDistribution: "MAIN_FEED",
      targetEntities: [],
      thirdPartyDistributionChannels: [],
    },
    content: {
      article: {
        source: articleUrl,
        title,
      },
    },
    lifecycleState: "PUBLISHED",
  });
}

Get Organization Page Info

async function getOrganization(accessToken: string, orgId: string) {
  const client = createLinkedInClient(accessToken);
  const { data } = await client.get(`/organizations/${orgId}`, {
    params: {
      projection: "(id,localizedName,vanityName,logoV2)",
    },
  });
  return data;
}

Token Refresh

async function refreshAccessToken(refreshToken: string) {
  const res = await fetch("https://www.linkedin.com/oauth/v2/accessToken", {
    method: "POST",
    headers: { "Content-Type": "application/x-www-form-urlencoded" },
    body: new URLSearchParams({
      grant_type: "refresh_token",
      refresh_token: refreshToken,
      client_id: process.env.LINKEDIN_CLIENT_ID!,
      client_secret: process.env.LINKEDIN_CLIENT_SECRET!,
    }),
  });
  return res.json();
}

Anti-Patterns

  • Omitting the LinkedIn-Version header - causes 400 errors or unexpected response formats on versioned endpoints.
  • Using deprecated v1 or legacy v2 endpoints - LinkedIn regularly deprecates endpoints; always use the latest documented versions.
  • Storing plain LinkedIn IDs instead of full URNs - API calls require the full URN format; storing just the numeric ID creates mapping bugs.
  • Assuming your app has access to all API products - each product (Share, Marketing, etc.) requires separate approval in the Developer Portal.

When to Use

  • Implementing "Sign in with LinkedIn" using OpenID Connect for professional applications.
  • Building tools that post content to personal LinkedIn feeds or organization pages.
  • Creating recruitment or HR platforms that need basic profile information from LinkedIn.
  • Automating social media management across multiple platforms including LinkedIn.
  • Building analytics dashboards for LinkedIn organization page performance.

Install this skill directly: skilldb add oauth-social-services-skills

Get CLI access →