authyo_plugin 1.1.2 copy "authyo_plugin: ^1.1.2" to clipboard
authyo_plugin: ^1.1.2 copied to clipboard

Add secure, multi-channel MFA (SMS, WhatsApp, Email, Call) to your Flutter app with Authyo. Fast, simple, and flexible.

example/lib/main.dart

import 'package:authyo_plugin/authyo_plugin.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';

/// Replace with the credentials from https://app.authyo.io → Applications.
const String kClientId = 'YOUR-CLIENT-ID';
const String kClientSecret = 'YOUR-CLIENT-SECRET';

/// Authyo server. Leave null for production (https://app.authyo.io). For a local
/// backend use e.g. 'http://10.0.2.2:5000' (Android emulator),
/// 'http://localhost:5000' (iOS simulator) or 'http://YOUR-LAN-IP:5000'
/// (physical device). Can also be passed with
/// `flutter run --dart-define=AUTHYO_BASE_URL=http://...`.
const String? kBaseUrl = String.fromEnvironment('AUTHYO_BASE_URL') == ''
    ? null
    : String.fromEnvironment('AUTHYO_BASE_URL');

void main() {
  runApp(const MyApp());
}

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

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Authyo Plugin',
      theme: ThemeData(
        colorSchemeSeed: const Color(0xFF2D398F),
        useMaterial3: true,
      ),
      home: const DemoPage(),
    );
  }
}

class DemoPage extends StatefulWidget {
  const DemoPage({super.key});

  @override
  State<DemoPage> createState() => _DemoPageState();
}

class _DemoPageState extends State<DemoPage> {
  final AuthyoService authyoService = AuthyoService.instance;
  final TextEditingController targetController = TextEditingController();
  final TextEditingController otpController = TextEditingController();

  bool useEmail = false;
  bool useBuiltInDialog = true;

  /// null = follow whatever is configured on the Authyo dashboard.
  AuthyoDesignStyle? selectedStyle;

  String? currentMaskId;
  AuthyoWidgetConfig? remoteConfig;
  bool sending = false;

  @override
  void initState() {
    super.initState();
    authyoService.init(
      clientId: kClientId,
      clientSecret: kClientSecret,
      baseUrl: kBaseUrl,
      showVerificationDialog: useBuiltInDialog,
      // Optional local overrides – comment out to follow the dashboard:
      // designStyle: AuthyoDesignStyle.glassmorphism,
      // theme: const AuthyoTheme(primary: Colors.teal),
    );
    authyoService.loadConfig().then((cfg) async {
      if (!mounted) return;
      setState(() => remoteConfig = cfg);
      // "Remember me" (dashboard option): prefill what the user asked us to
      // remember last time. Null when the option is off or nothing was kept.
      final remembered = await authyoService.rememberedIdentity();
      if (mounted && remembered != null && targetController.text.isEmpty) {
        setState(() {
          targetController.text = remembered;
          useEmail = remembered.contains('@');
        });
      }
    });
  }

  @override
  void dispose() {
    targetController.dispose();
    otpController.dispose();
    super.dispose();
  }

  void _snack(String msg) {
    ScaffoldMessenger.of(context)
      ..hideCurrentSnackBar()
      ..showSnackBar(SnackBar(content: Text(msg)));
  }

  Future<void> _sendOtp() async {
    FocusScope.of(context).unfocus();
    setState(() => sending = true);
    final res = await authyoService.sendOtp(
      ctx: context,
      to: targetController.text.trim(),
      authWay: useEmail ? AuthwayEnum.email : AuthwayEnum.sms,
      designStyle: selectedStyle,
      onVerificationComplete: (result) {
        if (result.error == null) {
          _snack('✅ Verified: ${result.result?.message}');
          setState(() => currentMaskId = null);
        } else {
          _snack('❌ ${result.error?.message}');
        }
      },
    );
    if (!mounted) return;
    setState(() => sending = false);

    if (res.error != null) {
      _snack('Oops! ${res.error?.message}');
      return;
    }
    final maskId = res.result?.data?.results
        ?.where((r) => r.maskId != null)
        .map((r) => r.maskId)
        .firstOrNull;
    _snack('OTP sent successfully');
    if (!useBuiltInDialog) setState(() => currentMaskId = maskId);
  }

  Future<void> _verifyOtp() async {
    final res = await authyoService.verifyOtp(
      maskId: currentMaskId ?? '',
      otp: otpController.text.trim(),
    );
    if (!mounted) return;
    if (res.error != null) {
      _snack('Oops! ${res.error?.message}');
    } else {
      _snack('✅ ${res.result?.message}');
      otpController.clear();
      setState(() => currentMaskId = null);
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('Authyo Plugin')),
      body: ListView(
        padding: const EdgeInsets.all(20),
        children: [
          _styleCard(),
          const SizedBox(height: 16),
          if (currentMaskId != null && !useBuiltInDialog)
            _customOtpCard()
          else
            _sendCard(),
        ],
      ),
    );
  }

  Widget _styleCard() {
    final cfg = remoteConfig;
    return Card(
      child: Padding(
        padding: const EdgeInsets.all(16),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            Text(
              'Dialog design',
              style: Theme.of(context).textTheme.titleMedium,
            ),
            const SizedBox(height: 8),
            DropdownButtonFormField<AuthyoDesignStyle?>(
              value: selectedStyle,
              decoration: const InputDecoration(
                labelText: 'Design style',
                border: OutlineInputBorder(),
              ),
              items: [
                DropdownMenuItem(
                  value: null,
                  child: Text(
                    'Follow dashboard'
                    '${cfg?.designStyle != null ? ' (${cfg!.designStyle!.label})' : ''}',
                  ),
                ),
                for (final s in AuthyoDesignStyle.values)
                  DropdownMenuItem(value: s, child: Text(s.label)),
              ],
              onChanged: (v) => setState(() => selectedStyle = v),
            ),
            SwitchListTile(
              contentPadding: EdgeInsets.zero,
              title: const Text('Use built-in verification dialog'),
              value: useBuiltInDialog,
              onChanged: (v) {
                setState(() {
                  useBuiltInDialog = v;
                  currentMaskId = null;
                });
                authyoService.setShowVerificationDialog(v);
              },
            ),
            if (cfg != null)
              Text(
                'Dashboard: ${cfg.authMethods.isEmpty ? 'no channels' : cfg.authMethods.join(', ')}'
                ' · ${cfg.socialLogins.length} social login(s)',
                style: Theme.of(context).textTheme.bodySmall,
              ),
          ],
        ),
      ),
    );
  }

  Widget _sendCard() {
    return Card(
      child: Padding(
        padding: const EdgeInsets.all(16),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.stretch,
          children: [
            TextField(
              controller: targetController,
              keyboardType: useEmail
                  ? TextInputType.emailAddress
                  : TextInputType.phone,
              inputFormatters: useEmail
                  ? const []
                  : [FilteringTextInputFormatter.allow(RegExp(r'[0-9+]'))],
              decoration: InputDecoration(
                labelText: useEmail ? 'Email address' : 'Phone number',
                hintText: useEmail ? 'jon@example.com' : '+911234567890',
                border: const OutlineInputBorder(),
              ),
            ),
            SwitchListTile(
              contentPadding: EdgeInsets.zero,
              title: const Text('Use email'),
              value: useEmail,
              onChanged: (v) {
                targetController.clear();
                setState(() => useEmail = v);
              },
            ),
            FilledButton(
              onPressed: sending ? null : _sendOtp,
              child: sending
                  ? const SizedBox(
                      height: 18,
                      width: 18,
                      child: CircularProgressIndicator(strokeWidth: 2),
                    )
                  : const Text('Send OTP'),
            ),
          ],
        ),
      ),
    );
  }

  Widget _customOtpCard() {
    return Card(
      child: Padding(
        padding: const EdgeInsets.all(16),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.stretch,
          children: [
            Text(
              'Custom UI – enter the OTP you received',
              style: Theme.of(context).textTheme.titleMedium,
            ),
            const SizedBox(height: 12),
            TextField(
              controller: otpController,
              keyboardType: TextInputType.number,
              textAlign: TextAlign.center,
              inputFormatters: [FilteringTextInputFormatter.digitsOnly],
              decoration: const InputDecoration(
                labelText: 'OTP',
                border: OutlineInputBorder(),
              ),
            ),
            const SizedBox(height: 12),
            FilledButton(
              onPressed: _verifyOtp,
              child: const Text('Verify OTP'),
            ),
            TextButton(
              onPressed: () => setState(() => currentMaskId = null),
              child: const Text('Cancel'),
            ),
          ],
        ),
      ),
    );
  }
}
2
likes
140
points
91
downloads

Documentation

Documentation
API reference

Publisher

verified publisherauthyo.io

Weekly Downloads

Add secure, multi-channel MFA (SMS, WhatsApp, Email, Call) to your Flutter app with Authyo. Fast, simple, and flexible.

Homepage
Repository (GitHub)
View/report issues

License

BSD-3-Clause (license)

Dependencies

dio, flutter, flutter_web_auth_2, plugin_platform_interface, shared_preferences, url_launcher

More

Packages that depend on authyo_plugin

Packages that implement authyo_plugin