Comment Ajouter une Authentification à une Application Electron
Si vous avez cherché comment ajouter une authentification à une application Electron, vous avez probablement trouvé des tutoriels qui ouvrent une BrowserWindow pour afficher un formulaire de connexion, interceptent le callback OAuth dans Electron, et stockent les tokens en texte clair. Cette approche est obsolète, non sécurisée, et entre en conflit avec le fonctionnement actuel d’OAuth 2.0 pour les applications natives.
Cet article explique l’architecture correcte : le flux Authorization Code avec PKCE, la connexion via le navigateur système, et un deep link ou une redirection loopback pour retourner les tokens à votre application.
Points Clés
- Les flux de connexion intégrés via
BrowserWindowviolent la RFC 8252 et exposent les utilisateurs à l’interception de leurs identifiants. Utilisez le navigateur système à la place. - PKCE (Proof Key for Code Exchange) remplace le secret client, qu’une application Electron ne peut pas stocker de manière sécurisée.
- Le deep linking avec un schéma d’URI personnalisé ou une redirection loopback retourne le code d’autorisation au processus principal.
- Stockez les refresh tokens avec
safeStorage, qui exploite la gestion des clés au niveau du système d’exploitation (Keychain, DPAPI, libsecret). - Isolez le processus renderer avec
contextIsolation: trueet n’exposez que des méthodes IPC ciblées viacontextBridge.
Pourquoi l’Authentification dans Electron Diffère de l’Authentification Web
Les applications Electron s’exécutent sur une machine contrôlée par l’utilisateur. Il n’existe pas de backend pour dissimuler un secret client, et il n’y a pas de sandbox navigateur isolant votre application du système d’exploitation. Cela modifie considérablement le modèle de menace.
La RFC 8252, le standard OAuth 2.0 spécifiquement rédigé pour les applications natives et de bureau, est explicite : n’utilisez pas de vues web intégrées pour les flux de connexion OAuth. Une BrowserWindow intégrée peut intercepter silencieusement les identifiants, et l’utilisateur n’a aucun moyen de vérifier qu’il communique avec un fournisseur d’identité légitime. Utilisez le navigateur système à la place.
L’Architecture Correcte : OAuth 2.0 PKCE avec Deep Linking
Le flux recommandé se présente comme suit :
- L’utilisateur clique sur « Se connecter » dans votre application Electron.
- Votre application ouvre le navigateur système avec une URL d’autorisation.
- L’utilisateur s’authentifie auprès de votre fournisseur d’identité (Auth0, Clerk, Firebase Authentication, AWS Cognito, ou tout fournisseur compatible OpenID Connect).
- Le fournisseur redirige vers un schéma d’URI personnalisé comme
myapp://auth/callbackou une adresse loopback commehttp://127.0.0.1:PORT/callback. - Le processus principal d’Electron intercepte cette redirection et échange le code d’autorisation contre des tokens.
- Les tokens sont stockés de manière sécurisée via
safeStorage.
Étant donné que les applications Electron ne peuvent pas conserver un secret client en sécurité, PKCE (Proof Key for Code Exchange) remplace entièrement ce secret. Avant le démarrage du flux, votre application génère un code_verifier aléatoire, le hache en un code_challenge, et envoie ce challenge avec la requête d’autorisation. Lors de l’échange du code contre des tokens, vous envoyez le code_verifier original. Le serveur d’autorisation vérifie leur correspondance. Aucun secret ne quitte jamais votre application.
Mise en Place du Deep Linking pour le Callback OAuth
Enregistrez un gestionnaire de protocole personnalisé dans votre processus principal :
// main.js
const { app } = require('electron');
const path = require('path');
if (process.defaultApp) {
if (process.argv.length >= 2) {
app.setAsDefaultProtocolClient('myapp', process.execPath, [
path.resolve(process.argv[1]),
]);
}
} else {
app.setAsDefaultProtocolClient('myapp');
}
// macOS : gérer le callback du deep link
app.on('open-url', (event, callbackUrl) => {
event.preventDefault();
handleAuthCallback(callbackUrl); // analyser le code, l'échanger contre des tokens
});
// Windows et Linux : les deep links arrivent via second-instance
const gotTheLock = app.requestSingleInstanceLock();
if (!gotTheLock) {
app.quit();
} else {
app.on('second-instance', (event, argv) => {
const callbackUrl = argv.find((arg) => arg.startsWith('myapp://'));
if (callbackUrl) handleAuthCallback(callbackUrl);
});
}
Sur Windows et Linux, l’événement second-instance transmet le deep link en tant qu’argument de ligne de commande. Sur macOS, open-url est l’événement approprié. Pour le packaging, configurez votre protocole dans electron-builder :
{
"protocols": {
"name": "myapp",
"schemes": ["myapp"]
}
}
Remarque : Sur macOS et Linux, le deep linking ne fonctionne généralement de manière fiable que dans les applications packagées, car le gestionnaire de protocole doit être enregistré auprès du système d’exploitation. Testez toujours le deep linking sur un build packagé, et non simplement avec
electron ..
Discover how at OpenReplay.com.
Stockage Sécurisé des Tokens avec Electron safeStorage
Ne stockez jamais les tokens dans localStorage, dans des fichiers en clair, ou dans electron-store sans chiffrement. Utilisez safeStorage, qui chiffre les données via la gestion des clés au niveau du système d’exploitation (Keychain sur macOS, DPAPI sur Windows, libsecret sur Linux) :
const { app, safeStorage } = require('electron');
const fs = require('fs');
const path = require('path');
const TOKEN_PATH = path.join(app.getPath('userData'), 'refresh.enc');
async function saveRefreshToken(token) {
if (!safeStorage.isEncryptionAvailable()) {
throw new Error('Encryption is not available on this system');
}
const encrypted = await safeStorage.encryptStringAsync(token);
fs.writeFileSync(TOKEN_PATH, encrypted);
}
async function loadRefreshToken() {
if (!fs.existsSync(TOKEN_PATH)) return null;
const encrypted = fs.readFileSync(TOKEN_PATH);
return await safeStorage.decryptStringAsync(encrypted);
}
Vérifiez toujours safeStorage.isEncryptionAvailable() avant de chiffrer, notamment sur Linux où le trousseau de clés du système d’exploitation peut ne pas être configuré. Sur certains systèmes Linux, Electron peut se replier sur un backend basic_text si aucun trousseau sécurisé n’est disponible. Vous pouvez inspecter le backend actif avec safeStorage.getSelectedStorageBackend() et avertir les utilisateurs en conséquence.
Isolation du Processus Renderer
Votre processus renderer ne devrait jamais manipuler les tokens directement. Utilisez contextIsolation, nodeIntegration: false, et n’exposez que ce dont le renderer a besoin via un contextBridge ciblé :
// preload.js
const { contextBridge, ipcRenderer } = require('electron');
contextBridge.exposeInMainWorld('auth', {
login: () => ipcRenderer.invoke('auth:login'),
logout: () => ipcRenderer.send('auth:logout'),
getProfile: () => ipcRenderer.invoke('auth:get-profile'),
});
Le processus principal gère toutes les opérations sur les tokens. Le renderer ne fait qu’appeler des méthodes IPC nommées. Cela limite l’impact en cas de compromission du renderer par du contenu malveillant.
Choix d’un Fournisseur d’Identité
L’architecture décrite ci-dessus fonctionne avec tout fournisseur compatible OpenID Connect. Les choix populaires pour les applications Electron incluent Auth0, Clerk, Firebase Authentication et AWS Cognito. Enregistrez votre application en tant qu’application de type Native ou Desktop auprès du fournisseur choisi, et configurez votre schéma d’URI personnalisé comme URI de redirection autorisée.
Le Modèle à Éviter
De nombreux tutoriels présentent encore ce modèle :
// ❌ Ne faites pas cela
const authWindow = new BrowserWindow({ /* ... */ });
authWindow.loadURL(authorizationUrl);
authWindow.webContents.session.webRequest.onBeforeRequest(
{ urls: ['http://localhost/callback*'] },
({ url }) => { /* intercept tokens */ }
);
Ce modèle intègre le flux de connexion dans Electron, ce qui viole la RFC 8252 et prive l’utilisateur de la possibilité de vérifier l’identité du fournisseur. Évitez-le, quel que soit le nombre de tutoriels qui le recommandent encore.
Conclusion
La bonne façon d’ajouter une authentification à une application Electron est simple : ouvrez le navigateur système, utilisez OAuth 2.0 avec PKCE, gérez le callback via le deep linking ou une redirection loopback, et stockez les tokens avec safeStorage. Maintenez le processus renderer isolé de toute logique liée aux tokens. Cette architecture est celle que recommande la RFC 8252, et c’est ce qu’attendent les fournisseurs modernes comme Auth0 et Clerk lorsque vous enregistrez une application native.
FAQ
Oui. Une redirection loopback utilise un serveur HTTP local sur 127.0.0.1 avec un port aléatoire pour recevoir le callback OAuth. Elle évite l'enregistrement du protocole au niveau du système d'exploitation et fonctionne bien pendant le développement. L'inconvénient est que vous devez démarrer et arrêter le serveur à chaque connexion, et certains fournisseurs exigent une configuration explicite des URI loopback dans leur tableau de bord.
Oui. Même si votre fournisseur émet un secret client, vous ne devriez pas l'intégrer dans un binaire Electron, car les utilisateurs peuvent l'extraire. PKCE protège l'échange du code d'autorisation, qu'un secret existe ou non. Enregistrez votre application en tant que client natif ou public afin que PKCE soit obligatoire et que le secret ne soit pas attendu.
Stockez uniquement le refresh token avec safeStorage. Lorsque l'access token expire, le processus principal envoie le refresh token au point de terminaison token du fournisseur et reçoit un nouvel access token. Conservez les access tokens en mémoire dans le processus principal, jamais dans le renderer. Si le refresh token est révoqué ou expiré, invitez l'utilisateur à se reconnecter via le navigateur système.
Les gestionnaires de protocoles personnalisés doivent être enregistrés auprès du système d'exploitation, et cet enregistrement s'effectue généralement lors de l'installation ou du packaging de l'application. L'exécution de electron . lance directement le binaire Electron, de sorte que le système d'exploitation ne sait pas que votre application gère le schéma myapp://. Testez toujours le deep linking sur un build packagé produit par electron-builder ou un outil similaire.
Gain Debugging Superpowers
Unleash the power of session replay to reproduce bugs, track slowdowns and uncover frustrations in your app. Get complete visibility into your frontend with OpenReplay — the most advanced open-source session replay tool for developers. Check our GitHub repo and join the thousands of developers in our community.