ExampleAuth

Flutter Auth Flow

A complete authentication flow covering app startup session check, login, registration, and logout using Koolbase Auth.

main.dart — startup session check

Check for an existing session on launch and route accordingly. Also handle version enforcement before showing the app.

lib/main.dartDart
import 'package:flutter/material.dart';
import 'package:koolbase/koolbase.dart';

void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await Koolbase.init(apiKey: 'pk_live_your_key_here');

  // Check version enforcement first
  final versionCheck = await Koolbase.version.check();
  if (versionCheck.status == VersionStatus.forceUpdate) {
    runApp(ForceUpdateApp(message: versionCheck.message));
    return;
  }

  // Check for existing session
  final user = await Koolbase.auth.currentUser();
  runApp(MyApp(initialRoute: user != null ? '/home' : '/login'));
}

class MyApp extends StatelessWidget {
  final String initialRoute;
  const MyApp({required this.initialRoute, super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      initialRoute: initialRoute,
      routes: {
        '/login': (_) => const LoginScreen(),
        '/register': (_) => const RegisterScreen(),
        '/home': (_) => const HomeScreen(),
      },
    );
  }
}

login_screen.dart

lib/screens/login_screen.dartDart
class LoginScreen extends StatefulWidget {
  const LoginScreen({super.key});

  @override
  State<LoginScreen> createState() => _LoginScreenState();
}

class _LoginScreenState extends State<LoginScreen> {
  final _emailCtrl = TextEditingController();
  final _passwordCtrl = TextEditingController();
  bool _loading = false;
  String? _error;

  Future<void> _login() async {
    setState(() { _loading = true; _error = null; });

    try {
      await Koolbase.auth.login(
        email: _emailCtrl.text.trim(),
        password: _passwordCtrl.text,
      );
      if (mounted) Navigator.pushReplacementNamed(context, '/home');
    } on KoolbaseAuthException catch (e) {
      setState(() {
        _error = switch (e.code) {
          'invalid_credentials' => 'Invalid email or password.',
          'email_not_verified'  => 'Please verify your email first.',
          _                     => 'Login failed. Please try again.',
        };
      });
    } finally {
      setState(() => _loading = false);
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Padding(
        padding: const EdgeInsets.all(24),
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            TextField(controller: _emailCtrl, decoration: const InputDecoration(labelText: 'Email')),
            const SizedBox(height: 12),
            TextField(controller: _passwordCtrl, obscureText: true, decoration: const InputDecoration(labelText: 'Password')),
            if (_error != null) ...[
              const SizedBox(height: 12),
              Text(_error!, style: const TextStyle(color: Colors.red)),
            ],
            const SizedBox(height: 24),
            ElevatedButton(
              onPressed: _loading ? null : _login,
              child: _loading ? const CircularProgressIndicator() : const Text('Login'),
            ),
            TextButton(
              onPressed: () => Navigator.pushNamed(context, '/register'),
              child: const Text('Create account'),
            ),
          ],
        ),
      ),
    );
  }
}

register_screen.dart

lib/screens/register_screen.dartDart
Future<void> _register() async {
  setState(() { _loading = true; _error = null; });

  try {
    await Koolbase.auth.register(
      email: _emailCtrl.text.trim(),
      password: _passwordCtrl.text,
    );

    // Send verification email
    await Koolbase.auth.sendVerificationEmail(
      email: _emailCtrl.text.trim(),
    );

    if (mounted) {
      showDialog(
        context: context,
        builder: (_) => AlertDialog(
          title: const Text('Verify your email'),
          content: const Text('We sent a verification link to your email. Click it to activate your account.'),
          actions: [TextButton(onPressed: () => Navigator.pop(context), child: const Text('OK'))],
        ),
      );
    }
  } on KoolbaseAuthException catch (e) {
    setState(() {
      _error = e.code == 'email_taken'
        ? 'An account with this email already exists.'
        : 'Registration failed. Please try again.';
    });
  } finally {
    setState(() => _loading = false);
  }
}

Logout

lib/screens/home_screen.dartDart
Future<void> _logout() async {
  await Koolbase.auth.logout();
  if (mounted) Navigator.pushReplacementNamed(context, '/login');
}

Session persistence

The session token is stored securely on device. On the next app launch, Koolbase.auth.currentUser() will return the user automatically — no login screen required until the session expires (30 days).