Intégration Auth0 Flutter Native (iOS/Android)
auth0_flutter est le SDK officiel Auth0 pour les applications Flutter. Sur mobile (iOS/Android), il effectue l'authentification via le navigateur système de l'appareil (Web Auth / Universal Login) et stocke les tokens de manière sécurisée dans le keychain/keystore de la plateforme via le CredentialsManager intégré, avec protection biométrique optionnelle.
Instruction agent : Avant de fournir les instructions de configuration du SDK, récupérez la dernière version de release en exécutant l'une des commandes suivantes :
gh api repos/auth0/auth0-flutter/releases/latest --jq '.tag_name'flutter pub info auth0_flutter 2>/dev/null | head -5Ou vérifiez sur pub.dev :
curl -s https://pub.dev/api/packages/auth0_flutter | python3 -c "import sys,json;print(json.load(sys.stdin)['latest']['version'])"Utilisez la version retournée dans toutes les lignes de dépendance à la place de toute version codée en dur ci-dessous. Version connue actuelle :
2.1.0.
Quand NE PAS utiliser
- Flutter web : Utilisez auth0-flutter-web — le web utilise une interface de plateforme différente (
Auth0Web) qui encapsule Auth0 SPA JS - iOS natif (Swift, sans Flutter) : Utilisez auth0-swift
- Android natif (Kotlin/Java, sans Flutter) : Utilisez auth0-android
- React Native : Utilisez auth0-react-native
- React SPA : Utilisez auth0-react
- Serveurs Node.js/Express : Utilisez auth0-express
Prérequis
- Flutter 3.24.0+
- Dart 3.5.0+
- Android : minSdkVersion 21+, compileSdkVersion 34+
- iOS : 14.0+ (les rappels de Universal Link nécessitent iOS 17.4+)
- Compte Auth0 — S'inscrire gratuitement
- CLI Auth0 — Instructions d'installation (utilisé pour créer et configurer l'application Auth0)
Flux de démarrage rapide
Instruction agent : Suivez ces étapes dans l'ordre. Si vous rencontrez une erreur à une étape quelconque, tentez de la corriger jusqu'à 5 fois avant d'appeler
AskUserQuestionpour demander des conseils à l'utilisateur. Recherchez toujours le code existant en premier — s'il existe déjà des gestionnaires de connexion/déconnexion, intégrez-vous à eux plutôt que d'en créer de nouveaux.
Étape 1 — Installer le SDK
Instruction agent : 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 à 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
Remarque : Le domaine Auth0 et l'ID client sont une configuration publique (pas des secrets) — une application native utilise PKCE sans secret client. Transmettez-les directement au constructeur
Auth0(domain, clientId); il n'est pas nécessaire de les stocker dans des variables d'environnement ou de les masquer.Instruction agent :
- Si les identifiants Auth0 (domaine ET ID client) sont déjà dans l'invite de l'utilisateur : Utilisez ces valeurs directement dans le constructeur
Auth0(...)et passez à l'étape 3.- Si aucun identifiant n'est fourni : Demandez à l'utilisateur quelle configuration il préfère en utilisant
AskUserQuestion: « Comment souhaitez-vous configurer l'application Auth0 — automatique (j'exécute la CLI Auth0 pour la créer) ou manuel (vous la créez dans le tableau de bord Auth0 et me donnez le domaine + ID client) ? »
- Automatique : Suivez les étapes de la CLI Auth0 dans le guide de configuration pour créer l'application native.
- Manuel : Demandez à l'utilisateur son domaine Auth0 et son ID client et utilisez-les directement.
Suivez Guide de configuration — Configuration Auth0 pour les vérifications préalables et la commande
auth0 apps create.
Étape 3 — Configurer Android
Instruction agent : Modifiez
android/app/build.gradle(oubuild.gradle.kts) et ajoutezmanifestPlaceholdersà l'intérieur deandroid { defaultConfig { ... } }. Ceux-ci fournissent l'URL de rappel que le filtre d'intentionRedirectActivitydu SDK enregistre — sans eux, l'application ne se compilera pas correctement pour Auth0.
Pour android/app/build.gradle (Groovy) :
android {
defaultConfig {
manifestPlaceholders = [auth0Domain: "YOUR_AUTH0_DOMAIN", auth0Scheme: "https"]
}
}
Pour android/app/build.gradle.kts (Kotlin DSL) :
android {
defaultConfig {
manifestPlaceholders["auth0Domain"] = "YOUR_AUTH0_DOMAIN"
manifestPlaceholders["auth0Scheme"] = "https"
}
}
Instruction agent : Utilisez
auth0Scheme: "https"pour utiliser Android App Links (recommandé). Si l'application cible un schéma personnalisé à la place, définissez-le sur une chaîne de schéma en minuscules et transmettez le même schéma àwebAuthentication(scheme: ...)en Dart. Voir le Guide de configuration pour plus de détails.
Étape 4 — Configurer iOS
Instruction agent : Pour le flux HTTPS par défaut (Universal Link) sur iOS 17.4+, aucune modification de
Info.plistn'est requise, mais la capacité Associated Domains doit être ajoutée dans Xcode (webcredentials:YOUR_AUTH0_DOMAIN). Pour les versions iOS plus anciennes ou un schéma d'URL personnalisé, ajoutez une entréeCFBundleURLTypesàios/Runner/Info.plist:
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleTypeRole</key>
<string>None</string>
<key>CFBundleURLName</key>
<string>auth0</string>
<key>CFBundleURLSchemes</key>
<array>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
</array>
</dict>
</array>
Étape 5 — Configurer les URL de rappel
Instruction agent : Enregistrez les URL de rappel et de déconnexion spécifiques à la plateforme à l'aide de la CLI Auth0. Déterminez le nom du package Android (à partir de
applicationIddansandroid/app/build.gradle) et l'identifiant de bundle iOS (à partir de Xcode /PRODUCT_BUNDLE_IDENTIFIER), puis exécutez la commande ci-dessous en remplaçant les espaces réservés (CLIENT_ID,YOUR_DOMAIN,ANDROID_PACKAGE_NAME,IOS_BUNDLE_ID) par les valeurs du projet :auth0 apps update CLIENT_ID \ --callbacks "https://YOUR_DOMAIN/android/ANDROID_PACKAGE_NAME/callback,https://YOUR_DOMAIN/ios/IOS_BUNDLE_ID/callback" \ --logout-urls "https://YOUR_DOMAIN/android/ANDROID_PACKAGE_NAME/callback,https://YOUR_DOMAIN/ios/IOS_BUNDLE_ID/callback" \ --no-input
Les formats d'URL de rappel sont :
- Android :
https://YOUR_DOMAIN/android/YOUR_PACKAGE_NAME/callback - iOS :
https://YOUR_DOMAIN/ios/YOUR_BUNDLE_ID/callback
Étape 6 — Implémenter l'authentification
Instruction agent : Recherchez le point d'entrée principal de l'application (
main.dart) dans le projet. Déterminez l'approche de gestion d'état :
- Recherchez les importations
provider,riverpod,bloc,GetXoumobx- Si aucune n'est trouvée, utilisez un
StatefulWidgetbasique avecsetStateEnsuite, 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 un simple setState ? »
StatefulWidget basique (Par défaut)
Instruction agent : Créez une classe
AuthService, puis intégrez-la au widget racine de l'application. Recherchez le widgetMaterialAppouCupertinoAppet mettez à jour en conséquence. Au démarrage, restaurez la session à partir du cacheCredentialsManager.
// lib/auth_service.dart
import 'package:auth0_flutter/auth0_flutter.dart';
class AuthService {
late final Auth0 _auth0;
Credentials? _credentials;
AuthService({required String domain, required String clientId}) {
_auth0 = Auth0(domain, clientId);
}
bool get isAuthenticated => _credentials != null;
UserProfile? get user => _credentials?.user;
/// Restaurez une session stockée au démarrage de l'application, si elle existe.
Future<void> init() async {
final hasValid = await _auth0.credentialsManager.hasValidCredentials();
if (hasValid) {
_credentials = await _auth0.credentialsManager.credentials();
}
}
/// Lancez Web Auth via le navigateur système. Les tokens sont stockés automatiquement.
Future<void> login() async {
_credentials = await _auth0
.webAuthentication()
.login(scopes: {'openid', 'profile', 'email', 'offline_access'});
}
/// Effacez la session dans le navigateur et supprimez les identifiants stockés.
Future<void> logout() async {
await _auth0.webAuthentication().logout();
await _auth0.credentialsManager.clearCredentials();
_credentials = null;
}
}
// lib/main.dart
import 'package:flutter/material.dart';
import 'package:auth0_flutter/auth0_flutter.dart'; // for WebAuthenticationException
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.init();
setState(() => _isLoading = false);
}
@override
Widget build(BuildContext context) {
return MaterialApp(
home: _isLoading
? const Scaffold(body: Center(child: CircularProgressIndicator()))
: _authService.isAuthenticated
? HomeScreen(authService: _authService, onChanged: _refresh)
: LoginScreen(authService: _authService, onChanged: _refresh),
);
}
void _refresh() => setState(() {});
}
class LoginScreen extends StatelessWidget {
final AuthService authService;
final VoidCallback onChanged;
const LoginScreen({super.key, required this.authService, required this.onChanged});
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: ElevatedButton(
onPressed: () async {
// Capturez le messenger avant l'await pour éviter d'utiliser
// BuildContext au-delà d'une lacune asynchrone.
final messenger = ScaffoldMessenger.of(context);
try {
await authService.login();
onChanged();
} on WebAuthenticationException catch (e) {
messenger.showSnackBar(
SnackBar(content: Text('Login failed: ${e.message}')),
);
}
},
child: const Text('Log In'),
),
),
);
}
}
class HomeScreen extends StatelessWidget {
final AuthService authService;
final VoidCallback onChanged;
const HomeScreen({super.key, required this.authService, required this.onChanged});
@override
Widget build(BuildContext context) {
final user = authService.user;
return Scaffold(
appBar: AppBar(
title: const Text('Home'),
actions: [
IconButton(
onPressed: () async {
await authService.logout();
onChanged();
},
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)
Instruction agent : 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';
class AuthService extends ChangeNotifier {
late final Auth0 _auth0;
Credentials? _credentials;
bool _isLoading = true;
AuthService({required String domain, required String clientId}) {
_auth0 = Auth0(domain, clientId);
}
bool get isAuthenticated => _credentials != null;
bool get isLoading => _isLoading;
UserProfile? get user => _credentials?.user;
Future<void> init() async {
if (await _auth0.credentialsManager.hasValidCredentials()) {
_credentials = await _auth0.credentialsManager.credentials();
}
_isLoading = false;
notifyListeners();
}
Future<void> login() async {
_credentials = await _auth0
.webAuthentication()
.login(scopes: {'openid', 'profile', 'email', 'offline_access'});
notifyListeners();
}
Future<void> logout() async {
await _auth0.webAuthentication().logout();
await _auth0.credentialsManager.clearCredentials();
_credentials = null;
notifyListeners();
}
}
// lib/main.dart — enveloppez 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 schémas complets avec Riverpod, Bloc, biométrie et scénarios avancés, voir Modèles d'intégration.
Étape 7 — Vérifier la compilation
Instruction agent : Exécutez une compilation pour vérifier que l'intégration se compile sans erreurs :
flutter build apk --debug # Android flutter build ios --no-codesign # iOS (sur macOS)Exécutez ensuite l'application sur un appareil ou un émulateur pour tester :
flutter runSi la compilation échoue, vérifiez les messages d'erreur et corrigez jusqu'à 5 fois avant de demander à l'utilisateur.
Test sur appareil physique : La protection biométrique (Face ID / Touch ID / empreinte digitale) ne peut pas être testée sur un simulateur/émulateur — le simulateur iOS et l'émulateur Android ont un matériel biométrique limité ou absent. Testez la biométrie et la redirection Universal Login complète sur un vrai appareil physique avant la publication.
Documentation détaillée
- Guide de configuration — Création d'application Auth0 via la CLI Auth0,
manifestPlaceholdersAndroid,Info.plistiOS / Associated Domains, enregistrement des URL de rappel - Modèles d'intégration — Connexion/déconnexion Web Auth, CredentialsManager, protection biométrique, schémas personnalisés, organisations, tokens d'accès API, modèles de gestion d'état, gestion des erreurs
- Référence API et test — Référence API complète, options de configuration, référence des claims, liste de vérification de test, dépannage
Erreurs courantes
| Erreur | Correction |
|---|---|
| Type d'application Auth0 non défini sur Native | Créez l'application avec auth0 apps create --type native (ou sélectionnez « Native » dans le tableau de bord Auth0) |
manifestPlaceholders manquant sur Android |
Ajoutez manifestPlaceholders = [auth0Domain: "...", auth0Scheme: "https"] à defaultConfig dans android/app/build.gradle — la compilation échoue sans cela |
Utilisation de Auth0Web sur mobile |
Mobile utilise la classe Auth0 avec webAuthentication(), pas Auth0Web (c'est l'API web uniquement) |
Importation de auth0_flutter_web.dart sur mobile |
Importez uniquement package:auth0_flutter/auth0_flutter.dart — l'importation _web est pour Flutter web |
| URL de rappel non correspondante | Enregistrez https://YOUR_DOMAIN/android/PACKAGE_NAME/callback et https://YOUR_DOMAIN/ios/BUNDLE_ID/callback dans les URL de rappel autorisées |
| Décalage de schéma entre Gradle et Dart | Si auth0Scheme est un schéma personnalisé, transmettez la même valeur à webAuthentication(scheme: 'myscheme') |
| Schéma personnalisé avec lettres majuscules sur Android | Les schémas personnalisés Android doivent être en minuscules |
| L'invite biométrique n'apparaît jamais sur Android | MainActivity doit étendre FlutterFragmentActivity (pas FlutterActivity) pour que l'invite biométrique fonctionne |
| Pas de stockage des identifiants après la connexion | webAuthentication().login() stocke automatiquement les identifiants ; ne les restockez pas à moins de les renouveler manuellement via api.renewCredentials |
| Pas de restauration de session au démarrage | Appelez credentialsManager.hasValidCredentials() + credentials() dans initState() pour restaurer la session |
Portée offline_access manquante |
Ajoutez 'offline_access' aux portées pour que le CredentialsManager puisse renouveler silencieusement les tokens d'accès expirés avec un token de rafraîchissement |
Capture d'une Exception générique |
Capturez WebAuthenticationException (connexion/déconnexion) et CredentialsManagerException (erreurs d'identifiants) et inspectez isUserCancelledException, isNoCredentialsFound, isTokenRenewFailed, etc. |
Compétences connexes
- auth0-quickstart — Configuration initiale Auth0 et création de compte
- auth0-flutter-web — Même SDK, plateforme web
- auth0-swift — iOS natif (Swift)
- auth0-android — Android natif (Kotlin/Java)
Référence rapide
| API | Objectif |
|---|---|
Auth0(domain, clientId) |
Créer le client SDK |
auth0.webAuthentication().login(...) |
Lancer Universal Login dans le navigateur système |
auth0.webAuthentication().logout() |
Effacer la session du navigateur |
auth0.webAuthentication(scheme: '...') |
Utiliser un schéma d'URL personnalisé |
auth0.credentialsManager.credentials() |
Obtenir les identifiants stockés (renouvelle automatiquement s'expirés) |
auth0.credentialsManager.hasValidCredentials() |
Vérifier une session stockée valide |
auth0.credentialsManager.clearCredentials() |
Supprimer les identifiants stockés |
LocalAuthentication(title: ...) |
Activer la protection biométrique des identifiants stockés |