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

+17 -21
View File
@@ -35,30 +35,26 @@ PORT=3000
NEXT_PUBLIC_SITE_URL=
# ---- Publication des promotions sur les réseaux sociaux ----
# Facultatif : si ces variables sont vides, le bouton correspondant n'apparaît
# pas dans le backoffice (le reste du site fonctionne normalement).
# Ce sont des SECRETS : ils ne doivent jamais être saisis dans le backoffice.
# La configuration se fait désormais dans Backend › Réseaux sociaux : on y colle
# les identifiants de l'application, on clique Connecter, et les jetons sont
# récupérés et stockés chiffrés automatiquement. Rien à mettre ici dans le cas
# normal.
#
# Facebook — page de l'association
# 1. Créer une app sur developers.facebook.com (type « Business »).
# 2. Ajouter le produit « Facebook Login » et les permissions
# pages_manage_posts + pages_read_engagement.
# 3. Générer un jeton de PAGE longue durée (Graph API Explorer puis
# /oauth/access_token?grant_type=fb_exchange_token) et le coller ci-dessous.
# Clé de chiffrement des jetons en base. Si elle est vide, AUTH_SECRET est
# utilisé. La définir explicitement permet de faire tourner AUTH_SECRET sans
# perdre les connexions réseaux.
# openssl rand -base64 32
SOCIAL_TOKEN_KEY=
# Versions d'API (facultatif)
FACEBOOK_GRAPH_VERSION=v21.0
LINKEDIN_API_VERSION=202506
# --- Repli historique ---
# Ces variables restent lues si aucun compte n'est connecté depuis le
# backoffice. Utile pour un jeton posé à la main ; sinon, laissez vide.
FACEBOOK_PAGE_ID=
FACEBOOK_PAGE_ACCESS_TOKEN=
# Version de la Graph API (facultatif)
FACEBOOK_GRAPH_VERSION=v21.0
#
# LinkedIn — page organisation
# 1. Créer une app sur linkedin.com/developers, la rattacher à la page
# « Association Plein R — Bassin de Pompey ».
# 2. Demander le produit « Community Management API ».
# 3. Générer un jeton avec les scopes w_organization_social + r_organization_social.
# L'URN se lit dans l'URL d'administration de la page (numéro d'organisation).
LINKEDIN_ORGANIZATION_URN=
# Alternative à l'URN : uniquement le numéro d'organisation
LINKEDIN_ORGANIZATION_ID=
LINKEDIN_ACCESS_TOKEN=
# Version de l'API LinkedIn (facultatif, format AAAAMM)
LINKEDIN_API_VERSION=202506