Sécurité des tokens Auth0 : prévenir XSS, CSRF et vol de session
Où stocker les tokens ? Comment prévenir le vol via XSS et CSRF ? Guide complet sur la sécurité des tokens dans les SPAs et applications mobiles.
Par Auth0.Expert · 2025-03-05 · 11 min de lecture
---
Sécurité des tokens Auth0 : XSS, CSRF et vol de session
TL;DR
Le vrai débat n'est pas "localStorage vs cookie" mais "quel niveau de risque acceptez-vous ?". Ce guide présente les menaces réelles et les mitigations concrètes.
---
Matrice des risques de stockage
Ce tableau compare les différents modes de stockage de tokens côté client, en évaluant leur exposition aux risques de XSS et CSRF.
| Stockage | Accessible JS | Envoyé auto | Risque XSS | Risque CSRF | |----------|--------------|-------------|------------|-------------| | localStorage | ✅ | ❌ | ⚠️ Élevé | ✅ Immunisé | | sessionStorage | ✅ | ❌ | ⚠️ Élevé | ✅ Immunisé | | Cookie HttpOnly | ❌ | ✅ | ✅ Immunisé | ⚠️ Vulnérable | | Cookie HttpOnly + SameSite=Strict | ❌ | Même domaine | ✅ Immunisé | ✅ Immunisé | | Mémoire (variable) | ✅ | ❌ | ✅ Survit pas refresh | ✅ Immunisé |
---
La solution BFF (Backend For Frontend)
La solution BFF consiste à gérer l’authentification et les tokens côté serveur pour renforcer la sécurité des applications SPA. Elle permet d’éviter l’exposition des tokens dans le navigateur et de limiter les risques de vol via XSS.
Browser (SPA)
↕ Cookie HttpOnly + SameSite=Strict (session ID)
BFF Server (Node/Python)
↕ Bearer Token (dans la mémoire du serveur)
API Backend
Ce code Node.js illustre comment le serveur BFF échange un code d'authentification contre un token, puis le stocke en session côté serveur, évitant ainsi d'exposer le token au browser.
// BFF: exchanging auth code for token (server-side)
app.get('/callback', async (req, res) => {
const { code } = req.query;
const tokenResponse = await auth0.getToken({ code });
// Stocker le token côté serveur, jamais envoyé au browser
req.session.accessToken = tokenResponse.access_token;
req.session.refreshToken = tokenResponse.refresh_token;
res.redirect('/dashboard');
});
// BFF: proxy les requêtes API
app.get('/api/data', async (req, res) => {
if (!req.session.accessToken) return res.status(401).json({});
const data = await fetch('https://api.example.com/data', {
headers: { Authorization: `Bearer ${req.session.accessToken}` }
});
res.json(await data.json());
});
Ce bloc assure que le token d'accès reste sur le serveur et que toutes les requêtes API sont signées en interne.
---
Content Security Policy : défense XSS
La mise en place d'une Content Security Policy (CSP) limite les sources de scripts et contenus, ce qui réduit la surface d'attaque XSS sur votre application.
// Express.js avec helmet
const helmet = require('helmet');
app.use(helmet.contentSecurityPolicy({
directives: {
defaultSrc: ["'self'"],
scriptSrc: ["'self'", "'nonce-RANDOM_NONCE'"],
styleSrc: ["'self'", "https://fonts.googleapis.com"],
imgSrc: ["'self'", "data:", "https://*.gravatar.com"],
connectSrc: [
"'self'",
"https://YOUR_DOMAIN.auth0.com",
"https://api.yourapp.com",
],
frameSrc: ["'none'"],
objectSrc: ["'none'"],
},
}));
---
CSRF Protection avec SameSite et CSRF Token
Pour protéger contre les attaques CSRF, il est recommandé d'utiliser les attributs de cookie SameSite et un token CSRF dédié pour les formulaires.
// Si vous utilisez des cookies pour les tokens
res.cookie('session', token, {
httpOnly: true, // Pas accessible via JS
secure: true, // HTTPS uniquement
sameSite: 'strict', // Jamais envoyé en cross-site
maxAge: 24 * 60 * 60 * 1000,
path: '/',
});
// Pour les formulaires : double submit cookie pattern
app.use(csrf({ cookie: true }));
app.get('/form', (req, res) => {
res.render('form', { csrfToken: req.csrfToken() });
});
Cette configuration assure que seuls les utilisateurs légitimes et authentifiés peuvent soumettre une demande.
---
Subresource Integrity (SRI)
L’ajout de Subresource Integrity permet de vérifier que le script CDN chargé n’a pas été altéré, ce qui protège contre des scripts malicieux injectés.
<!-- Protéger les scripts CDN -->
<script
src="https://cdn.auth0.com/js/auth0-spa-js/2.0/auth0-spa-js.production.js"
integrity="sha384-HASH_HERE"
crossorigin="anonymous"
></script>
---
Détection de token volé côté API
Pour détecter un token potentiellement volé, on peut vérifier contextuellement l’IP ou le pays d’origine lors de chaque requête API.
# Fingerprinting léger : stocker l'IP au moment du login
# Alerter si l'IP change drastiquement (pays différent)
async def validate_token_context(token_payload: dict, request: Request):
token_ip_country = token_payload.get('https://myapp.com/login_country')
current_country = get_country_from_ip(request.client.host)
if token_ip_country and token_ip_country != current_country:
# Log l'anomalie
await log_security_event('token_country_mismatch', {
'user': token_payload['sub'],
'token_country': token_ip_country,
'request_country': current_country,
})
# Ne pas bloquer (faux positifs VPN) mais alerter
Ce bloc permet d’alerter sur un changement suspect lors de l’utilisation du token, sans interrompre brutalement l’accès.
---
Checklist sécurité tokens
Voici une liste d'actions recommandées pour sécuriser le stockage et l’usage des tokens dans votre application Auth0.
- [ ] Tokens stockés en mémoire ou via BFF (pas localStorage si app sensible)
- [ ] Durée de vie courte : 15min access token, 30j refresh token
- [ ] Refresh Token Rotation activée
- [ ] CSP configuré
- [ ] SameSite=Strict si cookies
- [ ] HttpOnly si cookies
- [ ] Secure flag si cookies
- [ ] PKCE activé pour les SPAs
- [ ] Pas de token dans les URL (logs serveur)
- [ ] Silent refresh géré côté client
---
> 🔒 Audit de sécurité complet : analyse de votre chaîne d'authentification complète, identification des vulnérabilités et plan de remédiation priorisé.
Autres articles
- Auth0 et OAuth 2.0 : architecture complète pour comprendre les flux d'autorisation
- OpenID Connect sur Auth0 : ID Token, UserInfo et discovery endpoint expliqués
- Configurer SAML 2.0 avec Auth0 : guide complet pour l'entreprise
- Migrer des Rules vers les Auth0 Actions : guide pas à pas
- Architecture multi-tenant avec Auth0 : organisations, isolation et bonnes pratiques
- Validation des JWT Auth0 : RS256 vs HS256, JWKS et pièges communs
- Concevoir son architecture de tenants Auth0 : dev, staging, prod
- Configurer un domaine personnalisé Auth0 : login.votredomaine.com étape par étape