Intégration Auth0 Flutter Web
auth0_flutter est le SDK officiel Auth0 pour les applications Flutter. Sur la plateforme web, il enveloppe le SDK Auth0 SPA JS pour fournir une authentification basée sur le navigateur via des flux de redirection ou popup avec mise en cache des identifiants intégrée et renouvellement automatique des tokens.
Agent instruction: La version actuelle du SDK est
2.1.0. Utilisez cette version dans toutes les lignes de dépendance ci-dessous. Si vous avez besoin de vérifier, exécutezflutter pub add auth0_flutterqui résoudra automatiquement la dernière version compatible.
Quand NE PAS utiliser
- Flutter mobile (iOS/Android) : Utilisez auth0-flutter-native — mobile utilise une interface de plateforme différente avec Web Auth via le navigateur système
- iOS natif (Swift) : Utilisez auth0-swift
- Android natif (Kotlin/Java) : Utilisez auth0-android
- React SPA : Utilisez auth0-react
- Angular SPA : Utilisez auth0-angular
- Vue SPA : Utilisez auth0-vue
- Serveurs Node.js/Express : Utilisez auth0-express
Prérequis
- Flutter 3.24.0+
- Dart 3.5.0+
- Compte Auth0 — S'inscrire gratuitement
- Auth0 CLI — instructions d'installation (utilisé pour créer et configurer l'application Auth0)
Flux Quick Start
Agent instruction: Suivez ces étapes dans l'ordre. Si vous rencontrez une erreur à une étape, tentez de la corriger jusqu'à 5 fois avant d'appeler
AskUserQuestionpour demander des conseils à l'utilisateur. Cherchez toujours le code existant en premier — s'il y a déjà des gestionnaires de connexion/déconnexion, branchez-vous dessus plutôt que d'en créer de nouveaux.
Étape 1 — Installer le SDK
Agent instruction: Vérifiez le répertoire du projet pour
pubspec.yaml. S'il est présent, ajoutez la dépendance. S'il n'est pas trouvé, ce n'est pas un projet Flutter — demandez à l'utilisateur.Exécutez dans la racine du projet :
flutter pub add auth0_flutterVérifiez que la dépendance a été ajoutée à
pubspec.yaml:dependencies: auth0_flutter: ^2.1.0
Étape 2 — Configurer Auth0
Note: Pour les Single Page Applications, le domaine Auth0 et l'ID client sont une configuration publique (pas des secrets). Un SPA utilise PKCE sans secret client, et ces valeurs sont expédiées dans le bundle du navigateur. Passez-les directement au constructeur
Auth0Web(domain, clientId)— inutile de les stocker dans des variables d'environnement ou de les masquer.Agent instruction:
- Si les identifiants Auth0 (domaine ET ID client) sont déjà dans le prompt de l'utilisateur: Procédez à l'étape 3 et utilisez ces valeurs directement dans le constructeur
Auth0Web(...).- Si aucun identifiant n'est fourni: Créez l'application avec Auth0 CLI — NE DEMANDEZ PAS à l'utilisateur de créer ou configurer manuellement une application Auth0 dans le Dashboard. Utilisez toujours le chemin CLI.
Suivez Guide de configuration — Configuration Auth0 pour les vérifications préalables et la commande
auth0 apps create.
Étape 3 — Ajouter Auth0 SPA JS à index.html
Agent instruction:
- Localisez le point d'entrée web :
web/index.html- Ajoutez la balise de script Auth0 SPA JS à l'intérieur de
<head>:<script src="https://cdn.auth0.com/js/auth0-spa-js/2.1/auth0-spa-js.production.js" defer></script>Si
web/index.htmln'existe pas, l'utilisateur devra peut-être exécuterflutter create . --platforms=webpour ajouter le support web.
Étape 4 — Configurer les URL de callback
Agent instruction:
- Déterminez l'URL web de l'application. Pour le développement local, le défaut est
http://localhost:3000(lors de l'exécution avec--web-port 3000).- Posez à l'utilisateur via
AskUserQuestion: "Sur quel port exécuterez-vous votre application Flutter web localement ? (défaut : 3000)"- Enregistrez les URL de callback en utilisant Auth0 CLI (remplacez les valeurs réelles pour
CLIENT_ID,APP_URL) :auth0 apps update CLIENT_ID \ --callbacks "APP_URL" \ --logout-urls "APP_URL" \ --web-origins "APP_URL" \ --no-inputPour la production, ajoutez également l'URL de production à chaque liste.
Étape 5 — Implémenter l'authentification
Agent instruction: Cherchez le point d'entrée principal de l'application (
main.dart). Déterminez l'approche de gestion d'état :
- Cherchez les imports
provider,riverpod,bloc,GetX, oumobx- Si aucun n'est trouvé, utilisez
StatefulWidgetbasique avecsetStatePuis suivez uniquement le chemin correspondant ci-dessous. Si c'est ambigu, demandez via
AskUserQuestion: "Quelle approche de gestion d'état votre application Flutter utilise-t-elle — Provider, Riverpod, Bloc, ou setState basique ?"
StatefulWidget basique (Par défaut)
Agent instruction: Créez une classe
AuthService, puis intégrez-la dans le widget racine de l'application. Cherchez le widgetMaterialAppouCupertinoAppet mettez à jour en conséquence.
// lib/auth_service.dart
import 'package:auth0_flutter/auth0_flutter.dart';
import 'package:auth0_flutter/auth0_flutter_web.dart';
class AuthService {
late final Auth0Web _auth0;
Credentials? _credentials;
AuthService({required String domain, required String clientId}) {
_auth0 = Auth0Web(domain, clientId);
}
bool get isAuthenticated => _credentials != null;
Credentials? get credentials => _credentials;
UserProfile? get user => _credentials?.user;
/// Appelez au démarrage de l'application pour restaurer la session depuis le cache
Future<void> onLoad() async {
_credentials = await _auth0.onLoad();
}
/// Rediriger vers Auth0 Universal Login
Future<void> loginWithRedirect({String? redirectUrl}) async {
await _auth0.loginWithRedirect(
redirectUrl: redirectUrl,
scopes: {'openid', 'profile', 'email', 'offline_access'},
);
}
/// Ouvrir la connexion Auth0 dans une fenêtre popup
Future<void> loginWithPopup() async {
_credentials = await _auth0.loginWithPopup(
scopes: {'openid', 'profile', 'email', 'offline_access'},
);
}
/// Obtenir les identifiants en cache (renouvelle automatiquement s'ils ont expiré)
Future<Credentials> getCredentials() async {
final creds = await _auth0.credentials();
_credentials = creds;
return creds;
}
/// Vérifier si des identifiants valides existent
Future<bool> hasValidCredentials() async {
return await _auth0.hasValidCredentials();
}
/// Se déconnecter et rediriger vers l'application
Future<void> logout({String? returnToUrl}) async {
await _auth0.logout(returnToUrl: returnToUrl);
_credentials = null;
}
}
// lib/main.dart
import 'package:flutter/material.dart';
import 'auth_service.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatefulWidget {
const MyApp({super.key});
@override
State<MyApp> createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
final _authService = AuthService(
domain: 'YOUR_AUTH0_DOMAIN',
clientId: 'YOUR_AUTH0_CLIENT_ID',
);
bool _isLoading = true;
@override
void initState() {
super.initState();
_initAuth();
}
Future<void> _initAuth() async {
await _authService.onLoad();
setState(() => _isLoading = false);
}
@override
Widget build(BuildContext context) {
return MaterialApp(
home: _isLoading
? const Scaffold(body: Center(child: CircularProgressIndicator()))
: _authService.isAuthenticated
? HomeScreen(authService: _authService)
: LoginScreen(authService: _authService),
);
}
}
class LoginScreen extends StatelessWidget {
final AuthService authService;
const LoginScreen({super.key, required this.authService});
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: ElevatedButton(
onPressed: () => authService.loginWithRedirect(),
child: const Text('Log In'),
),
),
);
}
}
class HomeScreen extends StatelessWidget {
final AuthService authService;
const HomeScreen({super.key, required this.authService});
@override
Widget build(BuildContext context) {
final user = authService.user;
return Scaffold(
appBar: AppBar(
title: const Text('Home'),
actions: [
IconButton(
onPressed: () => authService.logout(
returnToUrl: Uri.base.origin,
),
icon: const Icon(Icons.logout),
),
],
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
if (user?.pictureUrl != null)
CircleAvatar(
backgroundImage: NetworkImage(user!.pictureUrl.toString()),
radius: 40,
),
const SizedBox(height: 16),
Text('Welcome, ${user?.name ?? 'User'}!'),
Text(user?.email ?? ''),
],
),
),
);
}
}
Provider (Gestion d'état)
Agent instruction: Si le projet utilise
provider, créezAuthServiceen tant queChangeNotifieret injectez-le viaChangeNotifierProviderà la racine de l'application.
// lib/auth_service.dart
import 'package:flutter/foundation.dart';
import 'package:auth0_flutter/auth0_flutter.dart';
import 'package:auth0_flutter/auth0_flutter_web.dart';
class AuthService extends ChangeNotifier {
late final Auth0Web _auth0;
Credentials? _credentials;
bool _isLoading = true;
AuthService({required String domain, required String clientId}) {
_auth0 = Auth0Web(domain, clientId);
}
bool get isAuthenticated => _credentials != null;
bool get isLoading => _isLoading;
UserProfile? get user => _credentials?.user;
Future<void> init() async {
_credentials = await _auth0.onLoad();
_isLoading = false;
notifyListeners();
}
Future<void> loginWithRedirect() async {
await _auth0.loginWithRedirect(
scopes: {'openid', 'profile', 'email', 'offline_access'},
);
}
Future<void> loginWithPopup() async {
_credentials = await _auth0.loginWithPopup(
scopes: {'openid', 'profile', 'email', 'offline_access'},
);
notifyListeners();
}
Future<void> logout() async {
await _auth0.logout(returnToUrl: Uri.base.origin);
_credentials = null;
notifyListeners();
}
}
// lib/main.dart — envelopper avec ChangeNotifierProvider
import 'package:provider/provider.dart';
void main() {
runApp(
ChangeNotifierProvider(
create: (_) => AuthService(
domain: 'YOUR_AUTH0_DOMAIN',
clientId: 'YOUR_AUTH0_CLIENT_ID',
)..init(),
child: const MyApp(),
),
);
}
Pour les modèles complets avec Riverpod, Bloc, et les scénarios avancés, voir Modèles d'intégration.
Étape 6 — Vérifier la compilation
Agent instruction: Lancez une compilation pour vérifier que l'intégration se compile sans erreurs :
flutter build webPuis lancez l'application localement pour tester :
flutter run -d chrome --web-port 3000Si la compilation échoue, examinez les messages d'erreur et corrigez jusqu'à 5 fois avant de demander à l'utilisateur.
Documentation détaillée
- Guide de configuration — Création d'application Auth0 via Auth0 CLI, configuration web/index.html, enregistrement des URL de callback
- Modèles d'intégration — Connexion par redirection, connexion par popup, gestion des identifiants, modèles de gestion d'état, support des organisations, gestion des erreurs
- Référence API et tests — Référence API complète, options de configuration, référence des claims, liste de vérification des tests, dépannage
Erreurs courantes
| Erreur | Correction |
|---|---|
| Type d'application Auth0 non défini sur Single Page Application | Dans Auth0 Dashboard, sélectionnez « Single Page Application » lors de la création de l'application |
Script Auth0 SPA JS manquant dans web/index.html |
Ajoutez <script src="https://cdn.auth0.com/js/auth0-spa-js/2.1/auth0-spa-js.production.js" defer></script> à <head> |
onLoad() non appelé au démarrage de l'application |
Appelez toujours onLoad() dans initState() ou équivalent pour restaurer les sessions après redirection |
Allowed Web Origins manquant dans Auth0 Dashboard |
Ajoutez l'URL de votre application (p. ex. http://localhost:3000) à Allowed Web Origins — requis pour le renouvellement silencieux des tokens |
Utilisation de l'API mobile auth0_flutter sur le web |
Importez à la fois package:auth0_flutter/auth0_flutter.dart (pour les types comme Credentials, UserProfile) ET package:auth0_flutter/auth0_flutter_web.dart (pour la classe Auth0Web) |
| L'import de base manquant cause des erreurs de type | Credentials et UserProfile sont exportés de auth0_flutter.dart, pas de auth0_flutter_web.dart — vous avez besoin des deux imports |
| Mismatch d'URL de callback | Assurez-vous que Allowed Callback URLs correspond exactement à l'URL où votre application s'exécute (y compris le port) |
--web-port non ajouté lors de l'exécution locale |
Utilisez flutter run -d chrome --web-port 3000 pour assurer une correspondance cohérente des ports avec les URL de callback |
| Popup bloquée par le navigateur | loginWithPopup() doit être appelée à partir d'une interaction utilisateur directe (clic de bouton) ; ne peut pas être appelée depuis initState() |
Scope offline_access manquant |
Ajoutez 'offline_access' à l'ensemble des scopes pour activer la rotation des tokens de rafraîchissement pour le renouvellement silencieux |
| Erreurs CORS sur l'endpoint de token | Assurez-vous que Allowed Web Origins est configuré dans Auth0 Dashboard (pas seulement Callback URLs) |