mcpField
A
auth0-flutter-web

auth0-flutter-web

github.com/auth0開発55203 回インストール1 日前に更新
リポジトリ

auth0-flutter-web について

auth0-flutter-webは、Flutter Web向けのAuth0連携スキルです。SDKの設定とブラウザー認証を案内し、リダイレクトやポップアップでのログイン、認証情報のキャッシュ、トークン更新を扱います。

主な機能

  1. 01Auth0 Flutter SDKの設定
  2. 02ブラウザーのリダイレクトとポップアップログイン
  3. 03認証情報のキャッシュとトークン更新
  4. 04状態管理パターンへの適応
  5. 05ビルド確認とトラブルシューティング

活用シーン

  1. 01Flutter WebアプリへのAuth0ログイン追加
  2. 02既存の状態管理に合わせた認証連携
  3. 03コールバックURLとWebオリジンの設定
  4. 04ビルドやトークン更新の問題確認

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/auth0/agent-skills --skill auth0-flutter-web

インストール後、Claude Code で/auth0-flutter-webを入力して読み込まれたか確認します。

同梱ファイル

SKILL.md と一緒にインストールされる参考資料やスクリプト。

references/
api.md
integration.md
setup.md
tests/
benchmark-config.json
evals.json
graders.json
graders.ts
package.json
run-evals.mjs

詳細

Auth0 Flutter Web インテグレーション

auth0_flutter は Flutter アプリケーション向けの公式 Auth0 SDK です。web プラットフォームでは、Auth0 SPA JS SDK をラップし、組み込みの認証情報キャッシュとトークンの自動更新機能を備えた、リダイレクトまたはポップアップフローによるブラウザベースの認証を提供します。

エージェントへの指示: 現在の SDK バージョンは 2.1.0 です。以下のすべての依存関係の行では、このバージョンを使用してください。確認する必要がある場合は、flutter pub add auth0_flutter を実行すると、互換性のある最新バージョンが自動的に解決されます。

使用しないケース

  • Flutter モバイル(iOS/Android):auth0-flutter-native を使用してください。モバイルでは、システムブラウザーを使った Web 認証を備える別のプラットフォームインターフェイスを使用します
  • ネイティブ iOS(Swift):auth0-swift を使用してください
  • ネイティブ Android(Kotlin/Java):auth0-android を使用してください
  • React SPA:auth0-react を使用してください
  • Angular SPA:auth0-angular を使用してください
  • Vue SPA:auth0-vue を使用してください
  • Node.js/Express サーバー:auth0-express を使用してください

前提条件

クイックスタートのワークフロー

エージェントへの指示: 以下の手順を順番に実行してください。どの手順でもエラーが発生した場合は、AskUserQuestion を呼び出してユーザーに案内を求める前に、最大 5 回まで修正を試みてください。必ず最初に既存のコードを検索してください。ログイン/ログアウトのハンドラーがすでにある場合は、新しく作成せず、そのハンドラーに組み込んでください。

ステップ 1 — SDK をインストールする

エージェントへの指示: プロジェクトディレクトリに pubspec.yaml があるか確認してください。存在する場合は、依存関係を追加してください。見つからない場合は Flutter プロジェクトではないため、ユーザーに確認してください。

プロジェクトのルートで実行します:

flutter pub add auth0_flutter

pubspec.yaml に依存関係が追加されたことを確認します:

dependencies:
  auth0_flutter: ^2.1.0
ステップ 2 — Auth0 を設定する

注: シングルページアプリケーションでは、Auth0 ドメインとクライアント ID は公開設定値(シークレットではありません)です。SPA はクライアントシークレットを使わずに PKCE を使用し、これらの値はブラウザーバンドルに含まれます。Auth0Web(domain, clientId) に直接渡してください。環境変数に保存したり、値を隠したりする必要はありません。

エージェントへの指示:

  • Auth0 の認証情報(ドメインとクライアント ID の両方)がユーザーのプロンプトにすでに含まれている場合: ステップ 3 に進み、Auth0Web(...) コンストラクターでそれらの値を直接使用してください。
  • 認証情報が提供されていない場合: Auth0 CLI でアプリケーションを作成してください。ユーザーにダッシュボードで Auth0 アプリケーションを手動で作成または設定するよう依頼してはいけません。必ず CLI を使用してください。

事前確認と auth0 apps create コマンドについては、セットアップガイド — Auth0 の設定に従ってください。

ステップ 3 — index.html に Auth0 SPA JS を追加する

エージェントへの指示:

  1. Web のエントリーポイントである web/index.html を見つけます
  2. <head> 内に Auth0 SPA JS のスクリプトタグを追加します:
<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 を実行する必要がある可能性があります。

ステップ 4 — コールバック URL を設定する

エージェントへの指示:

  1. アプリの Web URL を特定します。ローカル開発でのデフォルトは http://localhost:3000 です(--web-port 3000 を指定して実行する場合)。
  2. AskUserQuestion を使ってユーザーに質問します:"Flutter Web アプリをローカルで実行するポートを教えてください(デフォルト:3000)"
  3. Auth0 CLI を使ってコールバック URL を登録します(CLIENT_ID と APP_URL を実際の値に置き換えます):
auth0 apps update CLIENT_ID \
  --callbacks "APP_URL" \
  --logout-urls "APP_URL" \
  --web-origins "APP_URL" \
  --no-input

本番環境では、本番 URL も各リストに追加してください。

ステップ 5 — 認証を実装する

エージェントへの指示: プロジェクト内でメインアプリのエントリーポイント(main.dart)を検索します。状態管理の方式を特定してください。

  • provider、riverpod、bloc、GetX、または mobx のインポートを確認します
  • いずれも見つからない場合は、setState を使った基本的な StatefulWidget を使用します

次に、以下の該当するパスだけに従ってください。判断が難しい場合は、AskUserQuestion を使って次のように質問してください。「Flutter アプリではどの状態管理方式を使用していますか? Provider、Riverpod、Bloc、または基本的な setState のいずれですか?」

基本的な StatefulWidget(デフォルト)

エージェントへの指示: 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;

  /// 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});

  @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(状態管理)

エージェントへの指示: プロジェクトで 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 — 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(),
    ),
  );
}

Riverpod、Bloc、高度なシナリオの完全なパターンについては、Integration Patterns を参照してください。

ステップ 6 — ビルドを検証する

エージェントへの指示: ビルドを実行して、エラーなく統合がコンパイルされることを確認します。

flutter build web

次に、アプリをローカルで実行してテストします。

flutter run -d chrome --web-port 3000

ビルドに失敗した場合は、エラーメッセージを確認して修正します。ユーザーに尋ねる前に、最大 5 回まで修正を試みてください。

詳細ドキュメント

  • セットアップガイド — Auth0 CLI による Auth0 アプリケーションの作成、web/index.html の設定、コールバック URL の登録
  • 統合パターン — リダイレクトログイン、ポップアップログイン、認証情報の管理、状態管理パターン、組織サポート、エラー処理
  • API リファレンスとテスト — API リファレンス全般、設定オプション、クレームリファレンス、テストチェックリスト、トラブルシューティング

よくある間違い

間違い修正方法
Auth0 アプリの種類が Single Page Application に設定されていないAuth0 Dashboard でアプリケーションを作成する際に、「Single Page Application」を選択します
web/index.html に Auth0 SPA JS スクリプトがない<script src="https://cdn.auth0.com/js/auth0-spa-js/2.1/auth0-spa-js.production.js" defer></script> を <head> に追加します
アプリの起動時に onLoad() を呼び出していないリダイレクト後にセッションを復元できるよう、必ず initState() または同等の箇所で onLoad() を呼び出します
Auth0 Dashboard に Allowed Web Origins が設定されていないアプリの URL(例:http://localhost:3000)を Allowed Web Origins に追加します。サイレントトークン更新に必要です
Web で auth0_flutter のモバイル API を使用しているpackage:auth0_flutter/auth0_flutter.dart(Credentials、UserProfile などの型用)と package:auth0_flutter/auth0_flutter_web.dart(Auth0Web クラス用)の両方をインポートします
ベースとなるインポートがなく、型エラーが発生するCredentials と UserProfile は auth0_flutter_web.dart ではなく auth0_flutter.dart からエクスポートされています。両方のインポートが必要です
コールバック URL が一致しないAllowed Callback URLs がアプリの実行 URL と完全に一致していること(ポートを含む)を確認します
ローカルでの実行時に --web-port を指定していないコールバック URL のポートを確実に一致させるため、flutter run -d chrome --web-port 3000 を使用します
ブラウザーでポップアップがブロックされるloginWithPopup() はボタンクリックなど、ユーザーの直接操作から呼び出す必要があります。initState() からは呼び出せません
offline_access スコープがないサイレント更新でリフレッシュトークンのローテーションを有効にするには、スコープに 'offline_access' を追加します
トークンエンドポイントで CORS エラーが発生するAuth0 Dashboard で Allowed Web Origins が設定されていることを確認します(Callback URLs だけでは不十分です)

参考資料

コメント