LinkedIn API com JavaScript: Autenticação, Posts e Métricas sem SDK Oficial
O problema: a API do LinkedIn é hostil a quem vem do ecossistema JavaScript
A maioria das APIs de redes sociais oferece SDK oficial em JavaScript. O LinkedIn não. A documentação oficial mistura endpoints da API v1 (descontinuada), v2 (atual) e da Community Management API (lançada em 2023), sem distinção clara entre eles. O resultado: devs perdem horas testando endpoints que retornam 403 sem explicação, tokens que expiram sem refresh, e escopos que mudaram de nome entre versões.
Este post resolve três operações concretas: autenticar via OAuth 2.0, publicar posts programaticamente e ler métricas de engajamento. Tudo com fetch nativo, TypeScript e sem dependência de SDK de terceiros.
Se você precisa de contexto sobre como estruturar a camada HTTP entre sua aplicação e APIs externas, o post sobre API Layers em aplicações fullstack cobre exatamente essa arquitetura.
Antes de escodar: o que você precisa no LinkedIn Developer Portal
A API do LinkedIn exige um "app" registrado no portal de desenvolvedores. Dois pontos que a documentação não deixa óbvio:
-
Produtos determinam escopos. Você não escolhe escopos livremente. Precisa solicitar acesso ao produto "Share on LinkedIn" para publicar posts, e ao "Sign In with LinkedIn using OpenID Connect" para autenticação. Sem o produto aprovado, o escopo retorna erro silencioso no fluxo OAuth.
-
Tokens de acesso duram 60 dias. Tokens de refresh duram 365 dias, mas só estão disponíveis para apps com o produto "Advertising API" aprovado. Para a maioria dos casos (publicação e leitura de perfil), você trabalha apenas com o access token de 60 dias e precisa implementar re-autenticação.
| Produto LinkedIn | Escopos liberados | Token refresh disponível |
|---|---|---|
| Sign In with LinkedIn (OpenID Connect) | openid, profile, email | Não |
| Share on LinkedIn | w_member_social | Não |
| Advertising API | r_ads, r_ads_reporting | Sim (365 dias) |
| Community Management API | w_member_social, r_organization_social | Não |
Fluxo OAuth 2.0 passo a passo
O LinkedIn usa Authorization Code Flow. Nada de client credentials para ações em nome de usuários.
Passo 1: redirecionar o usuário para autorização
// linkedin-auth.ts
const LINKEDIN_AUTH_URL = "https://www.linkedin.com/oauth/v2/authorization";
interface LinkedInAuthParams {
clientId: string;
redirectUri: string;
// state previne CSRF: gere um valor aleatório e valide no callback
state: string;
}
function buildAuthorizationUrl(params: LinkedInAuthParams): string {
const searchParams = new URLSearchParams({
response_type: "code",
client_id: params.clientId,
redirect_uri: params.redirectUri,
state: params.state,
// escopos separados por espaço, não por vírgula
scope: "openid profile email w_member_social",
});
return `${LINKEDIN_AUTH_URL}?${searchParams.toString()}`;
}
Passo 2: trocar o authorization code por access token
// linkedin-token.ts
interface TokenResponse {
access_token: string;
expires_in: number;
scope: string;
}
async function exchangeCodeForToken(
code: string,
clientId: string,
clientSecret: string,
redirectUri: string
): Promise<TokenResponse> {
const response = await fetch(
"https://www.linkedin.com/oauth/v2/accessToken",
{
method: "POST",
headers: {
// LinkedIn exige form-urlencoded aqui, não JSON
"Content-Type": "application/x-www-form-urlencoded",
},
body: new URLSearchParams({
grant_type: "authorization_code",
code,
client_id: clientId,
client_secret: clientSecret,
redirect_uri: redirectUri,
}),
}
);
if (!response.ok) {
const error = await response.text();
throw new Error(`LinkedIn token exchange failed: ${response.status} ${error}`);
}
return response.json() as Promise<TokenResponse>;
}
Um detalhe que causa confu
Leia o artigo completo em https://www.vivodecodigo.com.br/backend/linkedin-api-javascript-oauth-posts-metricas-webdev