Intégration LinkedIn — Profil personnel Bernard¶
Contexte¶
Objectif : publier automatiquement sur le profil LinkedIn personnel de Bernard à chaque article publié sur tekdhi.dev. Ce document couvre la procédure complète depuis la création de l'app jusqu'au premier post réussi, ainsi que la correction des #open-graph tags pour un rendu riche.
Procédure complète — Obtenir le token OAuth¶
1. Créer l'app LinkedIn Developer¶
- Aller sur
https://www.linkedin.com/developers/apps/new - App name :
tekdhi-publisher - LinkedIn Page : sélectionner la page
tekdhi.dev(à créer si absente — gratuit surhttps://www.linkedin.com/company/setup/new/) - Logo obligatoire (n'importe quelle image)
- Cliquer Create app
2. Activer les produits requis (onglet Products)¶
Deux produits obligatoires — cliquer Request access sur chacun :
| Produit | Rôle | Scope accordé |
|---|---|---|
| Share on LinkedIn | Poster sur le profil | w_member_social |
| Sign In with LinkedIn using OpenID Connect | Accès profil + email | openid profile email |
⚠️ Sans le second produit, LinkedIn retourne une erreur 404 à l'ouverture de l'URL d'autorisation.
3. Configurer la Redirect URI (onglet Auth)¶
Ajouter : http://localhost:7654/callback
LinkedIn n'accepte pas les redirections HTTP vers une IP publique — localhost uniquement.
4. Récupérer Client ID et Client Secret (onglet Auth)¶
Valeurs à renseigner dans le script d'authentification.
5. Ouvrir le tunnel SSH depuis la machine locale¶
Dans un terminal local (pas le VPS) :
ssh -L 7654:localhost:7654 kanmaber@178.105.46.57 -N
Ce tunnel fait transiter localhost:7654 de la machine locale vers le VPS port 7654.
6. Lancer le script d'authentification sur le VPS¶
python3 /home/kanmaber/scripts/linkedin_auth.py
Le script : 1. Affiche l'URL d'autorisation LinkedIn 2. Lance un serveur HTTP sur le port 7654 3. Attend le callback LinkedIn (timeout : 5 min)
7. Ouvrir l'URL dans le navigateur et autoriser¶
LinkedIn affiche une page d'autorisation → cliquer Autoriser.
Le navigateur redirige vers localhost:7654/callback?code=... → tunnel → VPS → script capture le code → échange contre un token → sauvegarde.
8. Token sauvegardé¶
Fichier : /home/kanmaber/.tekdhi_social_tokens (chmod 600)
{
"linkedin": {
"access_token": "...",
"expires_in": 5183999,
"scope": "email,openid,profile,w_member_social",
"member_id": "_5gBQzvFxa",
"person_urn": "urn:li:person:_5gBQzvFxa"
}
}
⚠️ Token expire dans ~60 jours. Relancer
linkedin_auth.pypour renouveler.
Poster sur le profil LinkedIn¶
API utilisée¶
POST https://api.linkedin.com/v2/ugcPosts
Structure du payload¶
{
"author": "urn:li:person:_5gBQzvFxa",
"lifecycleState": "PUBLISHED",
"specificContent": {
"com.linkedin.ugc.ShareContent": {
"shareCommentary": { "text": "Texte du post..." },
"shareMediaCategory": "ARTICLE",
"media": [{
"status": "READY",
"description": { "text": "Extrait de l'article" },
"originalUrl": "https://tekdhi.dev/blog/slug-article",
"title": { "text": "Titre de l'article" }
}]
}
},
"visibility": {
"com.linkedin.ugc.MemberNetworkVisibility": "PUBLIC"
}
}
Commande curl de référence¶
TOKEN=$(python3 -c "import json; print(json.load(open('/home/kanmaber/.tekdhi_social_tokens'))['linkedin']['access_token'])")
curl -X POST https://api.linkedin.com/v2/ugcPosts \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-H "X-Restli-Protocol-Version: 2.0.0" \
-d "$PAYLOAD"
La réponse contient l'ID du post : {"id":"urn:li:share:XXXX"}.
Correction Open Graph — tekdhi.dev (SPA React)¶
Problème¶
tekdhi.dev est une SPA React. Les crawlers (LinkedIn, Twitter, Google) n'exécutent pas JavaScript → ils voient les OG tags par défaut du index.html au lieu de ceux de l'article.
Solution : bot detection Caddy + endpoint OG Express¶
Caddyfile (/home/kanmaber/shared_infra/Caddyfile)¶
tekdhi.dev {
@bot {
header_regexp User-Agent `(?i)(linkedinbot|twitterbot|facebookexternalhit|googlebot|bingbot|slackbot|whatsapp|telegram)`
path /blog/*
}
handle @bot {
rewrite * /og{path}
reverse_proxy 127.0.0.1:3902
}
handle {
root * /home/kanmaber/tekdhi-landing
try_files {path} /index.html
file_server
}
}
Quand un bot visite /blog/mon-slug → Caddy réécrit en /og/blog/mon-slug → Express sert du HTML statique avec les bonnes balises.
Route Express (server.ts)¶
Route ajoutée : GET /og/blog/:slug
Retourne un HTML minimal avec :
- og:type, og:url, og:title, og:description, og:image
- og:site_name, og:locale
- article:published_time, article:author
- name: author
- twitter:card, twitter:title, twitter:description, twitter:image
- <meta http-equiv="refresh"> pour rediriger les humains vers la vraie page
Image OG par défaut¶
Fichier : /home/kanmaber/tekdhi-landing/og-default.png
Source : /home/kanmaber/docs/tekdih_dev/Bannière2.png (PNG original, 3 Mo)
Utiliser le PNG directement — le format JPEG produit un rendu flou sur cette image.
Recharger Caddy après modification du Caddyfile¶
cd /home/kanmaber/shared_infra && docker compose restart caddy
Rebuilder le backend après modification de server.ts¶
cd /home/kanmaber/projets/tekdhi-site/BackEnd
npm run build
docker compose --env-file .env up -d --build
Vérifier l'aperçu LinkedIn¶
Post Inspector LinkedIn :
https://www.linkedin.com/post-inspector/inspect/https:%2F%2Ftekdhi.dev%2Fblog%2F<slug>
À faire¶
- [ ] Publication sur la LinkedIn Page tekdhi.dev — nécessite
w_organization_socialscope + URN de la page (ex:urn:li:organization:XXXXX) - [ ] Publication automatique au clic "Publier" — déclencher le post LinkedIn depuis le backend tekdhi quand
statutpasse deBROUILLONàPUBLIE
Liens connexes¶
- tekdhi/roadmap/notification-publication-article — plan global de diffusion : WhatsApp, Facebook, LinkedIn
- shared/architecture/shared-infra-docker — architecture Docker VPS : Caddy, shared_infra réseau
- shared/architecture/vps-ports-services — cartographie des ports VPS