Loading...
Loading...
Use when adding Auth0 login or logout to a Flutter web application. Integrates auth0_flutter on the web platform — use even if the user says "add login to my Flutter web app".
npx skill4agent add auth0/agent-skills auth0-flutter-webauth0_flutterAgent instruction: The current SDK version is. Use this version in all dependency lines below. If you need to verify, run2.1.0which will resolve the latest compatible version automatically.flutter pub add auth0_flutter
Agent instruction: Follow these steps in order. If you encounter an error at any step, attempt to fix it up to 5 times before callingto ask the user for guidance. Always search existing code first — if there are existing login/logout handlers, hook into them rather than creating new ones.AskUserQuestion
Agent instruction: Check the project directory for. If present, add the dependency. If not found, this is not a Flutter project — ask the user.pubspec.yamlRun in the project root:bashflutter pub add auth0_flutterVerify the dependency was added to:pubspec.yamlyamldependencies: auth0_flutter: ^2.1.0
Note: For Single Page Applications, the Auth0 Domain and Client ID are public configuration (not secrets). A SPA uses PKCE with no client secret, and these values ship in the browser bundle. Pass them directly to— there is no need to store them in environment variables or hide them.Auth0Web(domain, clientId)Agent instruction:
- If Auth0 credentials (domain AND client ID) are already in the user's prompt: Proceed to Step 3 and use those values directly in the
constructor.Auth0Web(...)- If no credentials are provided: Create the application with the Auth0 CLI — do NOT ask the user to create or configure an Auth0 application manually in the Dashboard. Always use the CLI path.
Follow Setup Guide — Auth0 Configuration for the pre-flight checks and thecommand.auth0 apps create
Agent instruction:
- Locate the web entry point:
web/index.html- Add the Auth0 SPA JS script tag inside
:<head>html<script src="https://cdn.auth0.com/js/auth0-spa-js/2.1/auth0-spa-js.production.js" defer></script>Ifdoes not exist, the user may need to runweb/index.htmlto add web support.flutter create . --platforms=web
Agent instruction:
- Determine the app's web URL. For local development, default is
(when running withhttp://localhost:3000).--web-port 3000- Ask the user via
: "What port will you run your Flutter web app on locally? (default: 3000)"AskUserQuestion- Register the callback URLs using the Auth0 CLI (substitute real values for
,CLIENT_ID):APP_URLbashauth0 apps update CLIENT_ID \ --callbacks "APP_URL" \ --logout-urls "APP_URL" \ --web-origins "APP_URL" \ --no-inputFor production, also add the production URL to each list.
Agent instruction: Search the project for the main app entry point (). Determine the state management approach:main.dart
- Look for
,provider,riverpod,bloc, orGetXimportsmobx- If none found, use basic
withStatefulWidgetsetStateThen follow only the matching path below. If ambiguous, ask via: "Which state management approach does your Flutter app use — Provider, Riverpod, Bloc, or basic setState?"AskUserQuestion
Agent instruction: Create anclass, then wire it into the app's root widget. Search for theAuthServiceorMaterialAppwidget and update accordingly.CupertinoApp
// 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;
/// Call on app startup to restore session from cache
Future<void> onLoad() async {
_credentials = await _auth0.onLoad();
}
/// Redirect to Auth0 Universal Login
Future<void> loginWithRedirect({String? redirectUrl}) async {
await _auth0.loginWithRedirect(
redirectUrl: redirectUrl,
scopes: {'openid', 'profile', 'email', 'offline_access'},
);
}
/// Open Auth0 login in a popup window
Future<void> loginWithPopup() async {
_credentials = await _auth0.loginWithPopup(
scopes: {'openid', 'profile', 'email', 'offline_access'},
);
}
/// Get cached credentials (auto-refreshes if expired)
Future<Credentials> getCredentials() async {
final creds = await _auth0.credentials();
_credentials = creds;
return creds;
}
/// Check if valid credentials exist
Future<bool> hasValidCredentials() async {
return await _auth0.hasValidCredentials();
}
/// Logout and redirect back to the app
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});
State<MyApp> createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
final _authService = AuthService(
domain: 'YOUR_AUTH0_DOMAIN',
clientId: 'YOUR_AUTH0_CLIENT_ID',
);
bool _isLoading = true;
void initState() {
super.initState();
_initAuth();
}
Future<void> _initAuth() async {
await _authService.onLoad();
setState(() => _isLoading = false);
}
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});
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});
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 ?? ''),
],
),
),
);
}
}Agent instruction: If the project uses, createprovideras aAuthServiceand inject it viaChangeNotifierat the app root.ChangeNotifierProvider
// 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 — wrap with 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(),
),
);
}Agent instruction: Run a build to verify the integration compiles without errors:bashflutter build webThen run the app locally to test:bashflutter run -d chrome --web-port 3000If the build fails, review error messages and fix up to 5 times before asking the user.
| Mistake | Fix |
|---|---|
| Auth0 app type not set to Single Page Application | In Auth0 Dashboard, select "Single Page Application" when creating the application |
Missing Auth0 SPA JS script in | Add |
Not calling | Always call |
Missing | Add your app URL (e.g., |
Using | Import both |
| Missing base import causes type errors | |
| Callback URL mismatch | Ensure |
Not adding | Use |
| Popup blocked by browser | |
Missing | Add |
| CORS errors on token endpoint | Ensure |