Loading...
Loading...
Compare original and translation side by side
auth0_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
auth0_flutterAgent指令: 当前SDK版本为。以下所有依赖项均使用此版本。如需验证,运行2.1.0,它会自动解析最新兼容版本。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指令: 按以下步骤依次操作。若在任何步骤遇到错误,尝试修复最多5次后,再调用向用户寻求指导。始终先搜索现有代码——如果已有登录/登出处理程序,应接入现有程序而非创建新程序。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
Agent指令: 检查项目目录中是否存在。若存在,添加依赖项;若未找到,则这不是Flutter项目——请询问用户。pubspec.yaml在项目根目录运行:bashflutter pub add auth0_flutter验证依赖项已添加至: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
注意: 对于单页应用,Auth0域名和客户端ID属于公开配置(并非机密)。单页应用使用PKCE(授权码流程+证明密钥),无需客户端密钥,这些值会随浏览器包一起发布。直接将其传入即可——无需存储在环境变量中或隐藏。Auth0Web(domain, clientId)Agent指令:
- 如果用户的提示中已提供Auth0凭证(域名和客户端ID): 继续步骤3,直接在
构造函数中使用这些值。Auth0Web(...)- 如果未提供凭证: 使用Auth0 CLI创建应用——不要让用户在控制台手动创建或配置Auth0应用。始终使用CLI方式。
遵循设置指南——Auth0配置进行预检检查,并执行命令。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指令:
- 找到Web入口文件:
web/index.html- 在
标签内添加Auth0 SPA JS脚本标签:<head>html<script src="https://cdn.auth0.com/js/auth0-spa-js/2.1/auth0-spa-js.production.js" defer></script>如果不存在,用户可能需要运行web/index.html来添加Web支持。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指令:
- 确定应用的Web URL。本地开发时,默认URL为
(使用http://localhost:3000运行时)。--web-port 3000- 通过
询问用户:"你本地运行Flutter Web应用将使用哪个端口?(默认:3000)"AskUserQuestion- 使用Auth0 CLI注册回调URL(将
、CLIENT_ID替换为实际值):APP_URLbashauth0 apps update CLIENT_ID \ --callbacks "APP_URL" \ --logout-urls "APP_URL" \ --web-origins "APP_URL" \ --no-input对于生产环境,还需将生产URL添加至每个列表中。
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指令: 搜索项目的主应用入口文件()。确定状态管理方式:main.dart
- 查找
、provider、riverpod、bloc或GetX导入语句mobx- 如果未找到,使用基础的
配合StatefulWidgetsetState然后仅遵循以下匹配的流程。若存在歧义,通过询问用户:"你的Flutter应用使用哪种状态管理方式——Provider、Riverpod、Bloc还是基础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指令: 创建类,然后将其接入应用的根组件。查找AuthService或MaterialApp组件并相应更新。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;
/// 应用启动时调用,从缓存恢复会话
Future<void> onLoad() async {
_credentials = await _auth0.onLoad();
}
/// 重定向至Auth0通用登录页面
Future<void> loginWithRedirect({String? redirectUrl}) async {
await _auth0.loginWithRedirect(
redirectUrl: redirectUrl,
scopes: {'openid', 'profile', 'email', 'offline_access'},
);
}
/// 在弹窗窗口中打开Auth0登录页面
Future<void> loginWithPopup() async {
_credentials = await _auth0.loginWithPopup(
scopes: {'openid', 'profile', 'email', 'offline_access'},
);
}
/// 获取缓存凭证(过期时自动刷新)
Future<Credentials> getCredentials() async {
final creds = await _auth0.credentials();
_credentials = creds;
return creds;
}
/// 检查是否存在有效凭证
Future<bool> hasValidCredentials() async {
return await _auth0.hasValidCredentials();
}
/// 登出并重定向回应用
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('登录'),
),
),
);
}
}
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('首页'),
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('欢迎,${user?.name ?? '用户'}!'),
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指令: 如果项目使用,将provider创建为AuthService,并通过ChangeNotifier在应用根节点注入。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 — 用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.
Agent指令: 运行构建命令以验证集成编译无错误:bashflutter build web然后在本地运行应用进行测试:bashflutter run -d chrome --web-port 3000如果构建失败,查看错误信息并尝试修复最多5次后再询问用户。
| 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 |
| 错误 | 修复方案 |
|---|---|
| Auth0应用类型未设置为单页应用 | 在Auth0控制台创建应用时选择“单页应用” |
| 在 |
应用启动时未调用 | 始终在 |
| Auth0控制台中缺少“允许的Web来源” | 将你的应用URL(例如 |
在Web平台使用 | 同时导入 |
| 缺少基础导入导致类型错误 | |
| 回调URL不匹配 | 确保“允许的回调URL”与应用运行的精确URL(包括端口)一致 |
本地运行时未添加 | 使用 |
| 弹窗被浏览器阻止 | |
缺少 | 在权限集合中添加 |
| 令牌端点出现CORS错误 | 确保在Auth0控制台中配置了“允许的Web来源”(不仅仅是回调URL) |