Connexion Facebook / LinkedIn en OAuth depuis le backoffice

Les jetons se posaient à la main dans docker-compose. Un écran Backend ›
Réseaux sociaux permet désormais de coller les identifiants de l'application,
cliquer Connecter, choisir la page, et ne plus y revenir.

- Table `social_accounts` : identifiants, jetons et cible par réseau. Tous les
  secrets sont chiffrés en AES-256-GCM (`src/lib/crypto.ts`), clé
  `SOCIAL_TOKEN_KEY` avec repli sur `AUTH_SECRET`.
- Routes `api/social/[network]/{connect,callback}` : `state` anti-CSRF en cookie
  httpOnly, échange du code, récupération des pages administrées. Aucun jeton ne
  transite par une URL — les cibles sont relistées côté serveur au moment de la
  sélection.
- Facebook : jeton utilisateur longue durée puis jeton de PAGE, qui n'expire
  pas. LinkedIn : jeton 60 jours, rafraîchi automatiquement si l'application a
  obtenu les jetons de rafraîchissement programmatiques.
- Faute de quoi le backoffice affiche la date d'expiration, un bandeau sur le
  tableau de bord à J-7 et un bouton Reconnecter.
- `social.ts` lit les identifiants via `social-accounts.ts` : base d'abord,
  variables d'environnement ensuite. Les installations existantes continuent de
  fonctionner sans modification.
- Le secret d'application n'est jamais renvoyé au navigateur : champ vide =
  valeur conservée.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QXNXRC4j5VLfKvpyyisrnb
This commit is contained in:
Claude committed 2026-07-24 23:00:08 +00:00
1 parent 8bc1b17fc5
commit 19d1104ab0
19 files changed
+2599 -82

No files matched your search

+39 -9
View File
@@ -102,12 +102,40 @@ Une promotion n'est jamais publiée deux fois : un réseau ayant déjà une
publication réussie est systématiquement ignoré, y compris sur un cycle
suspension → remise en ligne.
Les jetons d'accès sont des **secrets** : ils se configurent uniquement par
variables d'environnement (`FACEBOOK_PAGE_ID`, `FACEBOOK_PAGE_ACCESS_TOKEN`,
`LINKEDIN_ORGANIZATION_URN` ou `LINKEDIN_ORGANIZATION_ID`,
`LINKEDIN_ACCESS_TOKEN`), jamais depuis le backoffice. Voir
[`.env.example`](./.env.example) pour la marche à suivre côté Meta et LinkedIn.
Si un réseau n'est pas configuré, son bouton n'apparaît simplement pas.
### Connecter les comptes
Tout se passe dans **Backend › Réseaux sociaux** (administrateurs) : on colle les
identifiants de l'application, on clique **Connecter**, on choisit la page. Les
jetons sont récupérés par OAuth et stockés **chiffrés** (AES-256-GCM, clé
`SOCIAL_TOKEN_KEY` ou à défaut `AUTH_SECRET`) ; ils ne ressortent jamais vers le
navigateur. Un réseau non connecté voit simplement sa case disparaître du
formulaire de promotion.
L'écran affiche l'URL de redirection à déclarer sur le portail développeur —
c'est l'erreur de configuration la plus fréquente.
**Facebook.** Créez une application « Business » sur
[developers.facebook.com](https://developers.facebook.com/apps), ajoutez le
produit Connexion Facebook, déclarez l'URL de redirection. Gardez l'application
en **mode développement** avec le compte de l'association comme administrateur :
publier sur votre propre page ne demande alors aucune revue Meta. Le jeton de
page obtenu **n'expire pas** — une connexion suffit, définitivement.
**LinkedIn.** Créez une application sur
[linkedin.com/developers](https://www.linkedin.com/developers/apps) rattachée à
la page de l'association, puis demandez le produit **Community Management API**.
Deux limites à connaître avant de vous lancer :
- l'accès est soumis à une revue (page vérifiée, nom légal, adresse, politique
de confidentialité) ; ce n'est pas garanti ni immédiat ;
- les jetons LinkedIn durent **60 jours** et le rafraîchissement programmatique
est réservé à certains partenaires. En pratique il faut donc recliquer sur
**Reconnecter** environ tous les deux mois. Le backoffice affiche la date
d'expiration et un bandeau d'alerte 7 jours avant.
Les variables d'environnement (`FACEBOOK_PAGE_ACCESS_TOKEN`, etc.) restent lues
en **repli** si aucun compte n'est connecté, pour ne pas casser une installation
antérieure.
Les **liens publics** vers les deux pages (affichés sur l'accueil et dans le pied
de page) se règlent, eux, dans **Backend › Paramètres**.
@@ -143,9 +171,11 @@ Voir [`.env.example`](./.env.example). Les principales :
- `AUTH_URL` — URL publique de l'application
- `SEED_ON_START` — `true` pour seeder au démarrage du conteneur
- `SEED_ADMIN_EMAIL` / `SEED_ADMIN_PASSWORD` / `SEED_ADMIN_NAME` — premier admin
- `NEXT_PUBLIC_SITE_URL` — URL publique reprise dans les posts réseaux sociaux
- `FACEBOOK_PAGE_ID` / `FACEBOOK_PAGE_ACCESS_TOKEN` — publication Facebook (optionnel)
- `LINKEDIN_ORGANIZATION_URN` / `LINKEDIN_ACCESS_TOKEN` — publication LinkedIn (optionnel)
- `NEXT_PUBLIC_SITE_URL` — URL publique : sert au lien des posts **et** à l'adresse
de retour OAuth. Obligatoire pour connecter un réseau social.
- `SOCIAL_TOKEN_KEY` — clé de chiffrement des jetons réseaux (défaut : `AUTH_SECRET`)
- `FACEBOOK_PAGE_ID` / `FACEBOOK_PAGE_ACCESS_TOKEN`, `LINKEDIN_ORGANIZATION_URN` /
`LINKEDIN_ACCESS_TOKEN` — repli si aucun compte n'est connecté via le backoffice
## Note sur le logo