Yes, please! Here's the corrected README with all missing providers and fixed router examples:

# dot_auth

A Flutter package for phone and email-based Firebase authentication with Riverpod state management and GoRouter navigation — batteries included.

[![pub version](https://img.shields.io/badge/pub-v1.0.0-blue)](https://pub.dev)
[![license](https://img.shields.io/badge/license-MIT-green)](LICENSE)
[![Flutter](https://img.shields.io/badge/Flutter-3.x-blue)](https://flutter.dev)

---

## Table of Contents

- [Dependencies](#dependencies)
- [Quick Start](#quick-start)
  - [1. Setup Firebase](#1-setup-firebase)
  - [2. Initialize in main()](#2-initialize-in-main)
  - [3. Configure Router](#3-configure-router)
- [Providers](#providers)
  - [authStateProvider](#authstateprovider)
  - [currentUserProvider](#currentuserprovider)
  - [Convenience Providers](#convenience-providers)
  - [phoneAuthProvider](#phoneauthprovider)
  - [emailAuthProvider](#emailauthprovider)
- [Methods (Notifiers)](#methods-notifiers)
  - [Auth State Notifier](#auth-state-notifier)
  - [Phone Auth Notifier](#phone-auth-notifier)
  - [Email Auth Notifier](#email-auth-notifier)
- [AuthStatus Enum](#authstatus-enum)
- [Usage Examples](#usage-examples)
- [Custom Router (Manual Setup)](#custom-router-manual-setup)
- [Quick Reference Card](#quick-reference-card)

---

## Dependencies

Add the following to your `pubspec.yaml`:

```yaml
dependencies:
  dot_auth: ^1.0.0
  firebase_core: ^3.0.0
  firebase_auth: ^5.0.0
  flutter_riverpod: ^3.3.1
  go_router: ^17.3.0
  flutter_screenutil: ^5.9.0

Then run:

flutter pub get

Quick Start

1. Setup Firebase

Follow the Firebase setup guide for your platform. This generates firebase_options.dart.

2. Initialize in main()

import 'package:flutter/material.dart';
import 'package:firebase_core/firebase_core.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:dot_auth/dot_auth.dart';
import 'firebase_options.dart';

void main() async {
  WidgetsFlutterBinding.ensureInitialized();

  // Initialize ScreenUtil
  await ScreenUtil.ensureScreenSize();

  // Initialize Firebase
  await Firebase.initializeApp(
    options: DefaultFirebaseOptions.currentPlatform,
  );

  runApp(const ProviderScope(child: MyApp()));
}

3. Configure Router

class MyApp extends ConsumerWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    final router = AuthRouter.createRouter(
      ref: ref,
      homeRoute: '/home',
      homeBuilder: (context, state) => const HomePage(),
      email: true, // Enable email authentication
    );

    return ScreenUtilInit(
      designSize: const Size(360, 690),
      minTextAdapt: true,
      splitScreenMode: true,
      builder: (_, child) {
        return MaterialApp.router(
          title: 'My App',
          theme: authTheme(),
          routerConfig: router,
          debugShowCheckedModeBanner: false,
        );
      },
    );
  }
}

class HomePage extends ConsumerWidget {
  const HomePage({super.key});

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    final user = ref.watch(currentUserProvider);

    return Scaffold(
      appBar: AppBar(
        title: const Text('Home'),
        actions: [
          IconButton(
            icon: const Icon(Icons.logout),
            onPressed: () async {
              await ref.read(authStateProvider.notifier).signOut();
              if (context.mounted) {
                context.pushReplacement('/phone');
              }
            },
          ),
        ],
      ),
      body: Center(
        child: Text('Welcome ${user?.phoneNumber ?? user?.email ?? "User"}'),
      ),
    );
  }
}

Providers

authStateProvider

The main provider for authentication state. Watch this to get all auth-related information.

final authState = ref.watch(authStateProvider);

Auth State Properties

Property Type Description
status AuthStatus Current auth status (initial, loading, authenticated, unauthenticated, error)
isAuthenticated bool true if user is logged in
isLoading bool true if authentication is in progress
isUnauthenticated bool true if user is not logged in
user UserModel? Current user data or null
errorMessage String? Error message if authentication failed

User Properties (authState.user)

Property Type Description
uid String Unique user ID
phoneNumber String? User's phone number
email String? User's email address
displayName String? User's display name
photoURL String? User's photo URL
creationTime DateTime? Account creation time
lastSignInTime DateTime? Last login time
isEmailVerified bool Email verification status
isPhoneVerified bool Phone verification status
Widget build(BuildContext context, WidgetRef ref) {
  final authState = ref.watch(authStateProvider);

  if (authState.isAuthenticated) {
    return Text('Welcome ${authState.user?.phoneNumber ?? authState.user?.email}');
  }

  if (authState.isLoading) {
    return const CircularProgressIndicator();
  }

  if (authState.errorMessage != null) {
    return Text('Error: ${authState.errorMessage}');
  }

  return const Text('Please login');
}

currentUserProvider

A simplified provider that returns only the current user.

final user = ref.watch(currentUserProvider);
Widget build(BuildContext context, WidgetRef ref) {
  final user = ref.watch(currentUserProvider);

  if (user == null) return const Text('Not logged in');

  return Column(
    children: [
      Text('Phone: ${user.phoneNumber ?? "N/A"}'),
      Text('Email: ${user.email ?? "N/A"}'),
      Text('UID: ${user.uid}'),
      Text('Verified: ${user.isPhoneVerified}'),
      Text('Name: ${user.displayName ?? "No name"}'),
    ],
  );
}

Convenience Providers

These providers give you quick access to specific user properties without watching the full auth state.

// User information
final uid = ref.watch(currentUidProvider);          // String? - Firebase UID
final phone = ref.watch(currentPhoneProvider);      // String? - Phone number
final email = ref.watch(currentEmailProvider);      // String? - Email address

// Status flags
final isEmailVerified = ref.watch(isEmailVerifiedProvider);    // bool
final isPhoneVerified = ref.watch(isPhoneVerifiedProvider);    // bool

// Auth state
final isLoading = ref.watch(isAuthLoadingProvider);            // bool
final status = ref.watch(authStatusProvider);                  // AuthStatus
final error = ref.watch(authErrorProvider);                    // String?

Common usage:

Widget build(BuildContext context, WidgetRef ref) {
  final email = ref.watch(currentEmailProvider);
  final phone = ref.watch(currentPhoneProvider);
  final isVerified = ref.watch(isEmailVerifiedProvider);

  return Column(
    children: [
      Text('Email: ${email ?? "Not set"}'),
      Text('Phone: ${phone ?? "Not set"}'),
      if (isVerified) 
        const Icon(Icons.verified, color: Colors.green),
    ],
  );
}

phoneAuthProvider

Manages phone authentication state during the OTP process.

final phoneAuth = ref.watch(phoneAuthProvider);

OTP / Verification State Properties

Property Type Description
phoneNumber String? Entered phone number
verificationId String? Firebase verification ID
otpCode String? Entered OTP code
isCodeSent bool Whether the verification code was sent
isLoading bool Whether loading is in progress
error String? Error message if any
resendToken int? Resend token for Firebase
Widget build(BuildContext context, WidgetRef ref) {
  final phoneAuth = ref.watch(phoneAuthProvider);

  return Column(
    children: [
      if (phoneAuth.isLoading) const CircularProgressIndicator(),
      if (phoneAuth.error != null)
        Text('Error: ${phoneAuth.error}', style: TextStyle(color: Colors.red)),
      if (phoneAuth.isCodeSent)
        Text('Code sent to ${phoneAuth.phoneNumber}'),
      Text('Phone: ${phoneAuth.phoneNumber ?? "Not set"}'),
      Text('Code Sent: ${phoneAuth.isCodeSent}'),
    ],
  );
}

emailAuthProvider

Manages email/password authentication state.

final emailAuth = ref.watch(emailAuthProvider);

Email Auth State Properties

Property Type Description
email String? Entered email address
mode EmailAuthMode Current mode: .signIn, .signUp, .forgotPassword
isLoading bool Whether loading is in progress
error String? Error message if any
isPasswordResetSent bool Whether password reset email was sent
Widget build(BuildContext context, WidgetRef ref) {
  final emailAuth = ref.watch(emailAuthProvider);

  return Column(
    children: [
      if (emailAuth.isLoading) const CircularProgressIndicator(),
      if (emailAuth.error != null)
        Text('Error: ${emailAuth.error}', style: TextStyle(color: Colors.red)),
      if (emailAuth.isPasswordResetSent)
        const Text('Password reset email sent!'),
      Text('Email: ${emailAuth.email ?? "Not set"}'),
      Text('Mode: ${emailAuth.mode}'),
    ],
  );
}

Methods (Notifiers)

Auth State Notifier

final authNotifier = ref.read(authStateProvider.notifier);
Method Returns Description
signOut() Future<void> Signs out the current user
// Sign out user
await ref.read(authStateProvider.notifier).signOut();

// After sign out, navigate to login
if (context.mounted) {
  context.go('/login');
}

Note: AuthStateNotifier automatically manages loading and error states via the Firebase auth stream. You don't need to manually set these.


Phone Auth Notifier

final phoneNotifier = ref.read(phoneAuthProvider.notifier);
Method Returns Description
setPhoneNumber(String number) void Sets the phone number
setVerificationData(String verificationId, int? resendToken) void Sets the verification ID and optional resend token
setLoading(bool loading) void Sets the loading state
setError(String error) void Sets an error message
clearError() void Clears the current error
reset() void Resets all phone auth state
setOtp(String otp) void Sets the OTP code
ref.read(phoneAuthProvider.notifier).setPhoneNumber('+1234567890');
ref.read(phoneAuthProvider.notifier).setVerificationData('verification_id_here', 123);
ref.read(phoneAuthProvider.notifier).setLoading(true);
ref.read(phoneAuthProvider.notifier).setError('Invalid phone number');
ref.read(phoneAuthProvider.notifier).clearError();
ref.read(phoneAuthProvider.notifier).reset(); // use after OTP verification
ref.read(phoneAuthProvider.notifier).setOtp('123456');

Email Auth Notifier

final emailNotifier = ref.read(emailAuthProvider.notifier);
Method Returns Description
signIn(String email, String password) Future<void> Signs in with email and password
signUp(String email, String password) Future<void> Creates a new account
sendPasswordReset(String email) Future<void> Sends password reset email
setEmail(String email) void Sets the email address
setMode(EmailAuthMode mode) void Switches between sign in, sign up, forgot password
setLoading(bool loading) void Sets loading state
setError(String error) void Sets error message
clearError() void Clears error
reset() void Resets all email auth state

Email Auth Method Usage

// 1. Sign In with Email and Password
await ref.read(emailAuthProvider.notifier).signIn(
  'user@example.com',
  'password123',
);
// On success, authStateProvider updates automatically
if (context.mounted) context.go('/home');

// 2. Sign Up / Create Account
await ref.read(emailAuthProvider.notifier).signUp(
  'user@example.com',
  'password123',
);
// On success, authStateProvider updates automatically
if (context.mounted) context.go('/home');

// 3. Send Password Reset Email
await ref.read(emailAuthProvider.notifier).sendPasswordReset(
  'user@example.com',
);
// On success, isPasswordResetSent becomes true

// 4. Switch Mode
ref.read(emailAuthProvider.notifier).setMode(EmailAuthMode.signIn);
ref.read(emailAuthProvider.notifier).setMode(EmailAuthMode.signUp);
ref.read(emailAuthProvider.notifier).setMode(EmailAuthMode.forgotPassword);

// 5. Set Email
ref.read(emailAuthProvider.notifier).setEmail('user@example.com');

// 6. Set Loading
ref.read(emailAuthProvider.notifier).setLoading(true);

// 7. Set Error
ref.read(emailAuthProvider.notifier).setError('Invalid email or password');

// 8. Clear Error
ref.read(emailAuthProvider.notifier).clearError();

// 9. Reset State
ref.read(emailAuthProvider.notifier).reset();

Note: All error handling is internal. Methods set state.error instead of throwing exceptions.

EmailAuthMode Enum

enum EmailAuthMode {
  signIn,          // Sign in with email and password
  signUp,          // Create new account
  forgotPassword,  // Send password reset link
}

AuthStatus Enum

Value Description
AuthStatus.initial Initial state, not yet checked
AuthStatus.loading Loading — verifying or signing in
AuthStatus.authenticated User is authenticated
AuthStatus.unauthenticated User is not authenticated
AuthStatus.error An error occurred
final authState = ref.watch(authStateProvider);

switch (authState.status) {
  case AuthStatus.initial:
    return const Text('Initializing...');
  case AuthStatus.loading:
    return const CircularProgressIndicator();
  case AuthStatus.authenticated:
    return Text('Welcome ${authState.user?.phoneNumber ?? authState.user?.email}');
  case AuthStatus.unauthenticated:
    return const Text('Please login');
  case AuthStatus.error:
    return Text('Error: ${authState.errorMessage}');
}

Usage Examples

1. Check Authentication Status

Widget build(BuildContext context, WidgetRef ref) {
  final isAuthenticated = ref.watch(isAuthenticatedProvider);
  final authState = ref.watch(authStateProvider);

  if (authState.isLoading) {
    return const Center(child: CircularProgressIndicator());
  }

  if (isAuthenticated) {
    return Center(
      child: Text('Welcome ${authState.user?.phoneNumber ?? authState.user?.email}'),
    );
  }

  return const Center(child: Text('Please login'));
}

2. Get User Information

Widget build(BuildContext context, WidgetRef ref) {
  final user = ref.watch(currentUserProvider);

  return Card(
    margin: const EdgeInsets.all(16),
    child: Padding(
      padding: const EdgeInsets.all(16),
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          Text('UID: ${user?.uid ?? "N/A"}'),
          Text('Phone: ${user?.phoneNumber ?? "N/A"}'),
          Text('Email: ${user?.email ?? "N/A"}'),
          Text('Name: ${user?.displayName ?? "N/A"}'),
          Text('Phone Verified: ${user?.isPhoneVerified}'),
          Text('Email Verified: ${user?.isEmailVerified}'),
        ],
      ),
    ),
  );
}

3. Using Convenience Providers

Widget build(BuildContext context, WidgetRef ref) {
  final uid = ref.watch(currentUidProvider);
  final email = ref.watch(currentEmailProvider);
  final phone = ref.watch(currentPhoneProvider);
  final isVerified = ref.watch(isEmailVerifiedProvider);
  final isLoading = ref.watch(isAuthLoadingProvider);
  final status = ref.watch(authStatusProvider);

  if (isLoading) {
    return const Center(child: CircularProgressIndicator());
  }

  if (uid == null) {
    return const Center(child: Text('Please login'));
  }

  return Column(
    children: [
      Text('UID: $uid'),
      Text('Email: ${email ?? "Not set"}'),
      Text('Phone: ${phone ?? "Not set"}'),
      Text('Status: $status'),
      if (isVerified) 
        const Icon(Icons.verified, color: Colors.green),
    ],
  );
}

4. Handle Loading and Error States

Widget build(BuildContext context, WidgetRef ref) {
  final authState = ref.watch(authStateProvider);

  switch (authState.status) {
    case AuthStatus.loading:
      return const Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            CircularProgressIndicator(),
            SizedBox(height: 16),
            Text('Loading...'),
          ],
        ),
      );

    case AuthStatus.authenticated:
      return Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            const Icon(Icons.check_circle, size: 64, color: Colors.green),
            const SizedBox(height: 16),
            Text('Welcome ${authState.user?.phoneNumber ?? authState.user?.email}'),
          ],
        ),
      );

    case AuthStatus.error:
      return Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            const Icon(Icons.error, size: 64, color: Colors.red),
            const SizedBox(height: 16),
            Text('Error: ${authState.errorMessage}'),
            const SizedBox(height: 16),
            ElevatedButton(
              onPressed: () { /* retry logic */ },
              child: const Text('Retry'),
            ),
          ],
        ),
      );

    default:
      return const Center(child: Text('Please login'));
  }
}

5. Listen to Authentication Changes

class MyWidget extends ConsumerStatefulWidget {
  const MyWidget({super.key});

  @override
  ConsumerState<MyWidget> createState() => _MyWidgetState();
}

class _MyWidgetState extends ConsumerState<MyWidget> {
  @override
  void initState() {
    super.initState();

    ref.listen(authStateProvider, (previous, next) {
      if (next.isAuthenticated) {
        ScaffoldMessenger.of(context).showSnackBar(
          const SnackBar(content: Text('Logged in successfully!')),
        );
      } else if (next.isUnauthenticated) {
        ScaffoldMessenger.of(context).showSnackBar(
          const SnackBar(content: Text('Logged out')),
        );
      } else if (next.errorMessage != null) {
        ScaffoldMessenger.of(context).showSnackBar(
          SnackBar(content: Text('Error: ${next.errorMessage}')),
        );
      }
    });
  }

  @override
  Widget build(BuildContext context) {
    final authState = ref.watch(authStateProvider);
    return Scaffold(
      body: Center(child: Text('Status: ${authState.status}')),
    );
  }
}

6. Sign Out with Confirmation

Widget build(BuildContext context, WidgetRef ref) {
  return ElevatedButton(
    onPressed: () async {
      final shouldSignOut = await showDialog<bool>(
        context: context,
        builder: (context) => AlertDialog(
          title: const Text('Sign Out'),
          content: const Text('Are you sure you want to sign out?'),
          actions: [
            TextButton(
              onPressed: () => Navigator.pop(context, false),
              child: const Text('Cancel'),
            ),
            TextButton(
              onPressed: () => Navigator.pop(context, true),
              style: TextButton.styleFrom(foregroundColor: Colors.red),
              child: const Text('Sign Out'),
            ),
          ],
        ),
      );

      if (shouldSignOut == true) {
        await ref.read(authStateProvider.notifier).signOut();
        if (context.mounted) context.go('/login');
      }
    },
    style: ElevatedButton.styleFrom(
      backgroundColor: Colors.red,
      foregroundColor: Colors.white,
    ),
    child: const Text('Sign Out'),
  );
}

7. Phone Authentication State

Widget build(BuildContext context, WidgetRef ref) {
  final phoneAuth = ref.watch(phoneAuthProvider);

  return Column(
    children: [
      if (phoneAuth.isLoading) const LinearProgressIndicator(),

      if (phoneAuth.error != null)
        Container(
          padding: const EdgeInsets.all(12),
          margin: const EdgeInsets.all(8),
          decoration: BoxDecoration(
            color: Colors.red[50],
            borderRadius: BorderRadius.circular(8),
            border: Border.all(color: Colors.red),
          ),
          child: Text(phoneAuth.error!, style: const TextStyle(color: Colors.red)),
        ),

      if (phoneAuth.isCodeSent)
        Container(
          padding: const EdgeInsets.all(12),
          margin: const EdgeInsets.all(8),
          decoration: BoxDecoration(
            color: Colors.green[50],
            borderRadius: BorderRadius.circular(8),
            border: Border.all(color: Colors.green),
          ),
          child: Column(
            children: [
              const Text('Verification code sent!'),
              Text('To: ${phoneAuth.phoneNumber}'),
            ],
          ),
        ),

      const SizedBox(height: 16),
      Text('Phone: ${phoneAuth.phoneNumber ?? "Not set"}'),
      Text('Code Sent: ${phoneAuth.isCodeSent}'),
      Text('Loading: ${phoneAuth.isLoading}'),
    ],
  );
}

8. Protected Route

class ProtectedRoute extends ConsumerWidget {
  final Widget child;

  const ProtectedRoute({super.key, required this.child});

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    final isAuthenticated = ref.watch(isAuthenticatedProvider);
    final authState = ref.watch(authStateProvider);

    if (authState.isLoading) {
      return const Scaffold(
        body: Center(child: CircularProgressIndicator()),
      );
    }

    if (!isAuthenticated) {
      WidgetsBinding.instance.addPostFrameCallback((_) {
        context.pushReplacement('/login');
      });
      return const Scaffold(
        body: Center(child: CircularProgressIndicator()),
      );
    }

    return child;
  }
}

// Usage in router:
GoRoute(
  path: '/profile',
  builder: (context, state) => const ProtectedRoute(child: ProfilePage()),
),

Custom Router (Manual Setup)

If you build your own router instead of using AuthRouter.createRouter(), you must wire up RouterNotifier manually:

import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:go_router/go_router.dart';
import 'package:dot_auth/dot_auth.dart';

final routerProvider = Provider<GoRouter>((ref) {
  // Create RouterNotifier to listen to auth changes
  final routerNotifier = RouterNotifier(ref);
  
  return GoRouter(
    initialLocation: '/login',
    refreshListenable: routerNotifier,  // REQUIRED - enables auto-redirect
    redirect: routerNotifier.redirect,  // REQUIRED - uses default redirect logic
    routes: [
      // Auth routes
      GoRoute(
        path: '/login',
        name: 'login',
        builder: (context, state) => const AuthPhone(emailEnabled: true),
      ),
      GoRoute(
        path: '/otp',
        name: 'otp',
        builder: (context, state) => const OtpScreen(),
      ),
      GoRoute(
        path: '/email',
        name: 'email',
        builder: (context, state) => const AuthEmail(phoneEnabled: true),
      ),
      
      // Protected routes
      GoRoute(
        path: '/home',
        name: 'home',
        builder: (context, state) => const HomePage(),
        routes: [
          GoRoute(
            path: 'profile',
            name: 'profile',
            builder: (context, state) => const ProfilePage(),
          ),
        ],
      ),
      
      // Terms & Privacy routes (required for TcFooter)
      GoRoute(
        path: '/terms',
        builder: (context, state) => const TermsPage(),
      ),
      GoRoute(
        path: '/privacy',
        builder: (context, state) => const PrivacyPage(),
      ),
    ],
  );
});

Important: Omitting refreshListenable and redirect means the router will not react to auth state changes automatically. Your users would stay on the login page even after signing in.

Using in your app:

class MyApp extends ConsumerWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    final router = ref.watch(routerProvider);

    return MaterialApp.router(
      title: 'My App',
      theme: authTheme(),
      routerConfig: router,
      debugShowCheckedModeBanner: false,
    );
  }
}

Quick Reference Card

// ─── AUTH STATE ──────────────────────────────────────────────────────────

// 1. Check if user is logged in
final isAuth = ref.watch(isAuthenticatedProvider);

// 2. Get current user
final user = ref.watch(currentUserProvider);

// 3. Get full auth state
final authState = ref.watch(authStateProvider);

// 4. Auth state checks
authState.isAuthenticated     // bool
authState.isLoading           // bool
authState.status              // AuthStatus enum

// 5. Convenience providers
final uid = ref.watch(currentUidProvider);              // String?
final email = ref.watch(currentEmailProvider);          // String?
final phone = ref.watch(currentPhoneProvider);          // String?
final isEmailVerified = ref.watch(isEmailVerifiedProvider);    // bool
final isPhoneVerified = ref.watch(isPhoneVerifiedProvider);    // bool
final isLoading = ref.watch(isAuthLoadingProvider);            // bool
final status = ref.watch(authStatusProvider);                  // AuthStatus
final error = ref.watch(authErrorProvider);                    // String?

// 6. User data
user?.uid                     // String
user?.phoneNumber             // String?
user?.email                   // String?
user?.displayName             // String?
user?.photoURL                // String?
user?.creationTime            // DateTime?
user?.lastSignInTime          // DateTime?
user?.isEmailVerified         // bool
user?.isPhoneVerified         // bool

// 7. Sign out
await ref.read(authStateProvider.notifier).signOut();


// ─── PHONE AUTH ──────────────────────────────────────────────────────────

// 1. Watch phone auth state
final phoneAuth = ref.watch(phoneAuthProvider);

// 2. Phone auth properties
phoneAuth.phoneNumber         // String?
phoneAuth.verificationId      // String?
phoneAuth.otpCode             // String?
phoneAuth.isCodeSent          // bool
phoneAuth.isLoading           // bool
phoneAuth.error               // String?
phoneAuth.resendToken         // int?

// 3. Phone auth methods
ref.read(phoneAuthProvider.notifier).setPhoneNumber('+1234567890');
ref.read(phoneAuthProvider.notifier).setVerificationData('verification_id', 123);
ref.read(phoneAuthProvider.notifier).setLoading(true);
ref.read(phoneAuthProvider.notifier).setError('Invalid number');
ref.read(phoneAuthProvider.notifier).clearError();
ref.read(phoneAuthProvider.notifier).reset();
ref.read(phoneAuthProvider.notifier).setOtp('123456');


// ─── EMAIL AUTH ──────────────────────────────────────────────────────────

// 1. Watch email auth state
final emailAuth = ref.watch(emailAuthProvider);

// 2. Email auth properties
emailAuth.email               // String?
emailAuth.mode                // EmailAuthMode
emailAuth.isLoading           // bool
emailAuth.error               // String?
emailAuth.isPasswordResetSent // bool

// 3. Email auth methods
await ref.read(emailAuthProvider.notifier).signIn('user@example.com', 'password');
await ref.read(emailAuthProvider.notifier).signUp('user@example.com', 'password');
await ref.read(emailAuthProvider.notifier).sendPasswordReset('user@example.com');
ref.read(emailAuthProvider.notifier).setEmail('user@example.com');
ref.read(emailAuthProvider.notifier).setMode(EmailAuthMode.signIn);
ref.read(emailAuthProvider.notifier).setLoading(true);
ref.read(emailAuthProvider.notifier).setError('Invalid email');
ref.read(emailAuthProvider.notifier).clearError();
ref.read(emailAuthProvider.notifier).reset();

// 4. EmailAuthMode values
EmailAuthMode.signIn
EmailAuthMode.signUp
EmailAuthMode.forgotPassword


// ─── NAVIGATION ──────────────────────────────────────────────────────────

// Navigate after sign in/out
context.go('/home');
context.pushReplacement('/login');
context.pop();

Need Help?


License

MIT License — see LICENSE for details.


Made with ❤️ for the Flutter community

Libraries

dot_auth
dot_auth — Firebase phone OTP + email/password authentication for Flutter.