FIDO2 Passkeys en entreprise : adoption France 2026
Guide complet pour déployer les passkeys FIDO2 : WebAuthn, signCount et récupération de compte. Sécurisez vos accès entreprise sans mots de passe.
Introduction
Les passkeys FIDO2 remplacent les mots de passe par des clés publiques/privées, réduisant les risques d'usurpation et d'attaques par phishing. Ce guide explique comment intégrer des passkeys dans des environnements d'entreprise, avec des exemples concrets en JavaScript (navigator.credentials) et des conseils opérationnels pour la récupération de compte et la gouvernance.
Note d'accessibilité : certains termes techniques sont en anglais. Pour l'assistance des lecteurs d'écran, les termes anglais courants sont indiqués dans le mini-glossaire suivant avec l'attribut lang="en".
Mini-glossaire (termes techniques)
- Relying Party — l'application ou le serveur qui vérifie les preuves d'authentification.
- Attestation — preuve fournie à l'enregistrement pour prouver l'origine d'un authentifieur.
- Assertion — réponse signée par l'authentifieur lors d'une authentification.
Introduction aux passkeys FIDO2
Comprendre les passkeys
FIDO2 s'appuie sur un couple clé publique/clé privée. L'authentification se fait sans secret partagé stocké côté serveur : le serveur conserve la clé publique, tandis que la clé privée reste sur l'authentifieur (platform authenticator ou security key).
Les spécifications impliquées sont WebAuthn (API Web côté client) et CTAP (protocole côté authentifieur). Le flux principal est : enregistrement (attestation) → authentification (assertion).
- Clé publique / clé privée (pas de mot de passe côté serveur)
- Standards : WebAuthn + CTAP
- Plus grande résistance au phishing et aux credential stuffing
- Meilleure UX quand correctement intégrée
Exemple minimal côté client — enregistrement (navigator.credentials.create) :
const publicKeyOptions = {
challenge: Uint8Array.from(window.atob("BASE64_CHALLENGE"), c => c.charCodeAt(0)),
rp: { name: "Example Corp", id: "example.com" },
user: {
id: Uint8Array.from([1, 2, 3, 4]),
name: "alice@example.com",
displayName: "Alice"
},
pubKeyCredParams: [ { type: "public-key", alg: -7 } ],
timeout: 60000,
attestation: "none"
};
const credential = await navigator.credentials.create({ publicKey: publicKeyOptions });
// Send credential.response (attestation) to your server for verification
Le serveur doit vérifier l'attestation et stocker l'identifiant de la clé publique associée à l'utilisateur.
| Caractéristique | Description | Exemple / Persistance |
|---|---|---|
| Clé publique | Identifiant pour vérifier les signatures | Stockée côté serveur (credentialId, publicKey, signCount) |
| Clé privée | Stockée localement sur l'authentifieur | Jamais transmise |
| WebAuthn | API client standard | Navigateurs modernes (Chrome, Edge, Firefox, Safari) |
| Persistance | Platform vs Cross-platform | Platform authenticators stockent localement ; cross-platform (security keys) permettent portabilité |
Passkeys résidentes (Discoverable Credentials)
Les "discoverable credentials" (aussi appelées "resident keys") permettent au navigateur ou à la clé de retrouver l'identité de l'utilisateur sans que celui-ci saisisse un identifiant. Elles améliorent l'UX, notamment sur postes partagés ou pour la connexion par empreinte/bio sur mobile.
Pour demander une passkey résidente à l'enregistrement, on ajuste les options WebAuthn :
const residentOptions = {
challenge: Uint8Array.from(window.atob("BASE64_CHALLENGE"), c => c.charCodeAt(0)),
rp: { name: "Example Corp", id: "example.com" },
user: {
id: Uint8Array.from([1, 2, 3, 4]),
name: "alice@example.com",
displayName: "Alice"
},
pubKeyCredParams: [ { type: "public-key", alg: -7 } ],
residentKey: "required", // demander une clé résidente
userVerification: "preferred",
timeout: 60000
};
const cred = await navigator.credentials.create({ publicKey: residentOptions });
// Envoyer l'attestation au serveur
Considérations opérationnelles :
- Les passkeys résidentes facilitent le login sans identifiant mais augmentent les exigences de stockage côté authentifieur.
- Offrez-les en option et documentez le comportement multi-device (synchronisation via gestionnaires de plateforme si l'utilisateur l'autorise).
Pourquoi les entreprises adoptent les passkeys
Motivations techniques et métier
Les organisations migrent vers FIDO2 pour réduire l'exposition liée aux mots de passe, améliorer la conformité et renforcer la confiance client. En pratique, un déploiement bien conduit réduit notablement les incidents d'accès et les tickets de réinitialisation.
- Réduction des risques de phishing
- Conformité aux bonnes pratiques d'authentification forte
- Réduction de la charge opérationnelle liée aux resets de mots de passe
Avantages de la sécurité FIDO2
Bénéfices clés
FIDO2 apporte des gains opérationnels et de sécurité : diminution des coûts liés aux incidents d'accès, simplification de la gestion des identités et réduction de la fraude liée aux identifiants compromis. Les équipes IT voient une baisse des demandes de réinitialisation et un accroissement de la productivité.
- Réduction des coûts d'incidents et des tickets de support
- Gestion d'identités plus simple et plus robuste
- Meilleure expérience pour les utilisateurs finaux
Pour révoquer une passkey obsolète : supprimez l'enregistrement (credentialId) côté serveur et conservez un journal d'audit. Ne mettez pas simplement à jour un flag sans trace d'opération — conservez la traçabilité pour les enquêtes post‑incident.
Défis de l'adoption en entreprise
Obstacles techniques et organisationnels
Les obstacles courants incluent la compatibilité avec des applications legacy, la refactorisation des points d'authentification et la formation des équipes de support. Planifiez des pilotes cross-device et adaptez les intégrations SSO / IAM.
- Mises à jour de l'infrastructure d'authentification (SSO, reverse proxies)
- Compatibilité avec systèmes hérités
- Coûts de refactorisation pour certaines applications
- Besoins en formation et documentation
Flux d'authentification (diagramme)
Le diagramme ci‑dessous illustre le flux classique entre le client, l'authentifieur et la Relying Party (serveur).
Vérification du signCount (détection de clonage)
Le signCount est un compteur incrémental côté authentifieur : il augmente à chaque signature. Le serveur conserve le dernier signCount connu pour un credential. Lors d'une assertion, comparez le signCount reçu avec la valeur stockée :
- Si le nouveau signCount > storedSignCount → mise à jour normale (mettez à jour storedSignCount).
- Si le nouveau signCount ≤ storedSignCount → anomalie possible (clonage ou authentifieur défectueux) : déclenchez des vérifications additionnelles et alertez l'équipe sécurité.
Exemple serveur Node.js (vérification simplifiée du signCount) :
// Après vérification de l'assertion (par ex. avec fido2-lib)
// storedCredential.signCount est la valeur en base de données
// authr.signCount est la valeur extraite du résultat d'assertion
if (authr.signCount > storedCredential.signCount) {
// comportement normal : mettre à jour la base
storedCredential.signCount = authr.signCount;
await saveCredential(storedCredential);
} else {
// anomalie détectée : possible clonage
// actions recommandées : invalider la clé, notifier l'utilisateur, forcer vérifs supplémentaires
await handlePossibleClone(storedCredential.userId, storedCredential.id);
}
Attention : certains authenticators platform peuvent renvoyer 0 ou increment non fiable (implémentations anciennes). Combinez signCount avec d'autres signaux (géolocalisation, heuristiques de device) pour réduire les faux positifs.
Gestion de la récupération de compte
Principes et bonnes pratiques
La récupération de compte est critique : une mauvaise implémentation crée des vecteurs d'attaque. Préconisations :
- Ne jamais permettre une récupération sans vérification forte d'identité (KBA faible déconseillé).
- Proposer plusieurs options sécurisées : backup codes chiffrés, authentifieurs secondaires (clé de secours), synchronisation de passkeys via les gestionnaires de plateforme (si l'utilisateur l'accepte).
- Mettre en place une procédure humaine contrôlée pour la réinitialisation administrative : vérifications d'identité, journaux d'audit et approbation multi‑personne.
- Limiter la portée et la durée des jetons de réinitialisation et surveiller les tentatives anormales.
Exemple d'approche : backups chiffrés + clé secondaire
- Proposer à l'utilisateur de générer des codes de récupération (one-time backup codes) chiffrés côté serveur et téléchargeables.
- Permettre l'enregistrement d'un second authentifieur (security key) comme clé de secours.
- En cas de perte : vérification d'identité renforcée (document + selfie, validation via centre d'assistance), puis restitution contrôlée du compte et enregistrement d'une nouvelle passkey.
Considérations de sécurité
Conservez les preuves d'audit (logs) et appliquez des quotas pour éviter les abus de la procédure de récupération. Documentez la procédure pour le support, et automatisez les vérifications là où c'est sécuritaire.
Exemples de mise en œuvre réussie
Cas pratiques et métriques types
Approche conseillée : projet pilote sur un périmètre restreint (ex. équipes IT), mesurer les indicateurs puis déployer progressivement. Indicateurs à surveiller :
- Taux de succès d'enregistrement (objectif > 95% sur devices supportés)
- Baisse des tickets de réinitialisation (typique : diminution substantielle à suivre pendant 3-6 mois)
- Taux d'adoption utilisateur sur périmètre pilote
Exemples pratiques : une boutique qui a piloté sur le service clients et a vu une diminution des incidents d'accès ; un service financier qui a intégré biométrie platform authenticator pour les workflows sensibles. Commencez par comptes privilégiés et étendez par vagues.
Points clés
- Les passkeys FIDO2 augmentent la résistance au phishing et simplifient la gestion des identités quand elles sont bien intégrées.
- Testez via un projet pilote, adaptez l'IAM/SSO et préparez un plan de récupération sécurisé.
- Vérifiez et journalisez le signCount côté serveur pour détecter les anomalies.
- Utilisez navigator.credentials côté client et des bibliothèques serveur éprouvées (par ex.
fido2-libou@simplewebauthn/server) pour valider les réponses et stocker les credentials. - La gouvernance (audit, journaux, formation du support) est aussi importante que l'aspect technique.
Questions Fréquentes
- Comment intégrer FIDO2 dans une application existante ?
- Implémentez WebAuthn côté client (navigator.credentials.create / navigator.credentials.get) et ajoutez la vérification d'attestation/assertion côté serveur. Utilisez des bibliothèques serveur reconnues (par ex.
fido2-libou@simplewebauthn/server) pour valider les réponses et stocker les credentials (credentialId, publicKey, signCount). Mettez en place un projet pilote et adaptez votre SSO/IAM si nécessaire. - Quels sont les principaux défis de l'adoption ?
- Compatibilité des applications héritées, besoin de formation et définition d'une stratégie de récupération. Prévoyez un budget pour la refactorisation des points d'authentification critiques et formalisez la procédure de secours sécurisée.
- Les passkeys sont-elles compatibles avec tous les navigateurs et appareils ?
- Les navigateurs récents (Chrome, Edge, Firefox, Safari) supportent WebAuthn ; de nombreux smartphones récents incluent des platform authenticators. Testez vos flux sur les appareils et versions utilisés par vos utilisateurs avant déploiement.
- Que faire en cas de perte d'une clé physique ?
- Mettez en place une procédure de récupération sécurisée : codes de secours chiffrés, clé secondaire enregistrée, et procédure administrative contrôlée (vérification d'identité). Évitez les solutions basées uniquement sur questions KBA faibles.
- Qu'est-ce que le signCount et pourquoi est-il important ?
- Le signCount est un compteur incrémental fourni par l'authentifieur. Le serveur doit comparer la valeur reçue à la valeur stockée pour détecter des usages anormaux (clonage). En cas d'anomalie (nouveau count ≤ ancien count), lancez des vérifications supplémentaires.
- Que sont les passkeys résidentes (discoverable credentials) ?
- Ce sont des credentials stockés côté authentifieur permettant à l'authentifieur de s'identifier sans que l'utilisateur saisisse un identifiant. Elles améliorent l'UX (ex. login par biométrie) mais nécessitent des choix UX/ops (optionnelle vs obligatoire).
Conclusion
Les passkeys FIDO2 offrent une trajectoire claire vers une authentification plus sûre et plus pratique. Pour réussir, combinez déploiements pilotes, intégration technique (navigator.credentials + vérification serveur), procédures de récupération robustes et formation des équipes. Commencez par un périmètre restreint et industrialisez ensuite le processus.
Annexe — Exemples JavaScript et Node.js
Authentification : navigation (assertion)
// Récupération d'un challenge depuis le serveur, puis appel navigator.credentials.get
const publicKeyGet = {
challenge: Uint8Array.from(window.atob("BASE64_CHALLENGE"), c => c.charCodeAt(0)),
allowCredentials: [
{
id: base64ToArrayBuffer("BASE64_CREDENTIAL_ID"),
type: "public-key"
}
],
timeout: 60000,
userVerification: "preferred"
};
const assertion = await navigator.credentials.get({ publicKey: publicKeyGet });
// Envoyer assertion.response au serveur pour vérification
Vérification côté serveur (extrait, fido2-lib)
import { Fido2Lib } from "fido2-lib";
const f2l = new Fido2Lib({
rpId: "example.com",
rpName: "Example Corp",
timeout: 60000,
challengeSize: 32
});
// attestationResponse provient du client (credential.response)
// IMPORTANT: expectedChallenge doit provenir de la session utilisateur (par ex. req.session.challenge)
const expectedChallenge = req.session.challenge; // récupérer depuis la session utilisateur
const attestationExpectations = {
challenge: expectedChallenge,
origin: "https://app.example.com",
factor: "either"
};
const regResult = await f2l.attestationResult(attestationResponse, attestationExpectations);
// regResult contient la clé publique à stocker (regResult.authnrData)
Exemple de vérification d'assertion + mise à jour signCount (simplifié)
// assertionResponse provient du client
// expectedChallenge récupéré depuis la session (comme ci-dessus)
const assertionExpectations = {
challenge: expectedChallenge,
origin: "https://app.example.com",
factor: "either",
publicKey: storedCredential.publicKey,
prevCounter: storedCredential.signCount
};
const authnResult = await f2l.assertionResult(assertionResponse, assertionExpectations);
const authr = authnResult.authnrData;
// Vérification et gestion du signCount (voir section dédiée)
if (authr.signCount > storedCredential.signCount) {
storedCredential.signCount = authr.signCount;
await updateCredentialInDb(storedCredential);
} else {
await handlePossibleClone(storedCredential.userId, storedCredential.id);
}
Bibliothèques recommandées côté serveur : fido2-lib (pour contrôles bas‑niveau) ou @simplewebauthn/server (APIs plus haut niveau). Testez les versions compatibles avec votre stack (Node.js 18+ recommandé pour les nouvelles applications).