Un client venait de reprendre la main sur un compte administrateur après avoir soupçonné qu’un ancien prestataire en gardait l’accès. Changer le mot de passe lui semblait suffisant. Ce n’est pas le cas : sur WordPress, une session déjà ouverte reste valide même après un changement de mot de passe, tant que le cookie d’authentification correspondant n’a pas expiré ou été explicitement révoqué. Il fallait donc aller couper les sessions actives une par une, ou plutôt toutes en une fois.
WordPress gère ses sessions via la classe WP_Session_Tokens, présente depuis la version 4.0. Elle mérite d’être connue de tout développeur qui travaille sur l’authentification ou qui doit intervenir après un incident de sécurité, car c’est le seul outil qui donne une vue fiable des connexions actives d’un compte.
Comment WordPress stocke les sessions actives
Chaque connexion réussie génère un jeton de session stocké dans la méta utilisateur session_tokens, sous forme d’un tableau associatif contenant, pour chaque session, l’horodatage de création, l’horodatage d’expiration, l’adresse IP d’origine et l’agent utilisateur du navigateur. Ce tableau permet à un même compte d’avoir plusieurs sessions valides simultanément, typiquement un ordinateur de bureau et un téléphone.
La classe WP_Session_Tokens (et son implémentation concrète WP_User_Meta_Session_Tokens) fournit une API propre pour lire et manipuler ce tableau sans le manipuler à la main, ce qui évite de corrompre le format interne.
Lister les sessions actives d’un utilisateur

$user_id = 42;
$manager = WP_Session_Tokens::get_instance( $user_id );
$sessions = $manager->get_all();
foreach ( $sessions as $token => $session ) {
printf(
"Connecté depuis %s, expire le %s, IP %s\n",
date( 'd/m/Y H:i', $session['login'] ),
date( 'd/m/Y H:i', $session['expiration'] ),
$session['ip'] ?? 'inconnue'
);
}
Cette boucle affiche, pour chaque session ouverte, sa date de connexion, sa date d’expiration prévue et l’adresse IP associée. C’est exactement ce type d’information qu’il faut examiner après un doute sur la compromission d’un compte : une session ouverte depuis une IP inconnue, ou dont la date de connexion ne correspond à aucune activité légitime du titulaire du compte, est un signal fort.
Déconnecter un compte de partout après un incident
Une fois le mot de passe changé, la révocation explicite de toutes les sessions garantit qu’aucune connexion antérieure ne reste valide, y compris celles ouvertes sur des appareils que l’utilisateur légitime ne contrôle plus ou dont il ignore l’existence :
$manager = WP_Session_Tokens::get_instance( $user_id );
$manager->destroy_all();
Il est utile de savoir que WordPress appelle déjà cette méthode automatiquement dans certains cas : un changement de mot de passe via l’écran de profil déclenche destroy_all() pour ce compte. En revanche, ce n’est pas automatique si le mot de passe est modifié directement en base de données ou via WP-CLI sans passer par les fonctions natives, d’où l’intérêt de connaître cette classe pour l’appeler explicitement dans ce cas.
Pour un compte précis, WP-CLI propose directement la commande wp user session destroy, qui accepte l’identifiant ou le login de l’utilisateur et l’option --all pour couper toutes ses sessions d’un coup :
wp user session destroy 42 --all
Pour couvrir l’ensemble des comptes du site après un incident large, il suffit de boucler la commande sur la liste des utilisateurs :
wp user list --field=ID | xargs -I{} wp user session destroy {} --all
Ne révoquer qu’une session spécifique
Il arrive qu’on veuille couper une seule session suspecte sans déconnecter l’utilisateur légitime de son propre appareil. La méthode destroy() prend en paramètre le jeton précis à invalider :
$manager = WP_Session_Tokens::get_instance( $user_id );
$manager->destroy( $token_suspect );
Le jeton en question s’obtient en parcourant le tableau retourné par get_all(), en identifiant la session dont les caractéristiques (IP, horodatage) correspondent à celle que l’on souhaite couper.
Limiter le nombre de sessions simultanées par compte
Pour des comptes à privilèges élevés, certaines équipes choisissent d’imposer une session unique par utilisateur, afin qu’une nouvelle connexion déconnecte automatiquement les précédentes. Cela se fait en s’accrochant au filtre attach_session_information ou plus simplement en interceptant l’action wp_login pour appeler destroy_others(), qui conserve la session courante et révoque toutes les autres :
add_action( 'wp_login', function ( $user_login, $user ) {
if ( in_array( 'administrator', (array) $user->roles, true ) ) {
$manager = WP_Session_Tokens::get_instance( $user->ID );
$current_token = wp_get_session_token();
$manager->destroy_others( $current_token );
}
}, 10, 2 );
Cette approche convient bien aux comptes administrateurs sur des sites sensibles, mais elle peut gêner des utilisateurs qui alternent légitimement entre plusieurs appareils. À réserver aux rôles où le compromis sécurité/confort penche clairement vers la sécurité.
Vérifier la durée de vie des sessions
La durée par défaut d’une session (deux jours, quatorze jours avec la case « se souvenir de moi ») se filtre avec auth_cookie_expiration, utile à raccourcir sur des comptes sensibles pour réduire la fenêtre d’exposition en cas de vol de cookie.
Après chaque changement de prestataire technique sur un site client, notre routine inclut désormais systématiquement un
destroy_all()sur les comptes administrateurs, en plus du changement de mot de passe. Un réflexe qui coûte une commande et referme une porte qu’on oublie trop souvent.
En résumé
Changer un mot de passe ne suffit pas à couper l’accès d’un ancien prestataire ou d’un attaquant qui dispose déjà d’un cookie de session valide. La classe WP_Session_Tokens, associée à la commande WP-CLI wp user session, donne le contrôle complet nécessaire pour lister, auditer et révoquer les connexions actives d’un compte, un réflexe à intégrer systématiquement après tout incident touchant à l’authentification.