Skip to main content

thirdfactor_kyc 1.2.0 copy "thirdfactor_kyc: ^1.2.0" to clipboard
thirdfactor_kyc: ^1.2.0 copied to clipboard

ThirdFactor / Obsidian KYC — Flutter client SDK. Opens the hosted verification flow in a WebView and returns one normalized result. Native ePassport/eID NFC reading plugs in via the thirdfactor_kyc_nf [...]

example/lib/main.dart

// Minimal example app for the thirdfactor_kyc Flutter SDK.
//
// Paste a hosted session URL (from your backend's POST /v3/session/ call),
// tap "Start verification", and the normalized result is shown below.
//
// Native NFC chip reading comes from the thirdfactor_kyc_nfc companion package
// (git-distributed; see its README) and is injected via `nfcReader:` — the
// core SDK works without it, falling back to the flow's server-side NFC path.

import 'package:flutter/material.dart';
import 'package:thirdfactor_kyc/thirdfactor_kyc.dart';
import 'package:thirdfactor_kyc_nfc/thirdfactor_kyc_nfc.dart';

void main() => runApp(const ExampleApp());

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

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'ThirdFactor KYC Example',
      theme: ThemeData(useMaterial3: true, colorSchemeSeed: Colors.indigo),
      home: const HomeScreen(),
    );
  }
}

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

  @override
  State<HomeScreen> createState() => _HomeScreenState();
}

class _HomeScreenState extends State<HomeScreen> {
  final _urlController = TextEditingController();

  /// The injected NFC chip reader from thirdfactor_kyc_nfc. Passed to
  /// ThirdFactor.verify so the hosted flow can delegate its NFC step to the
  /// device, and used directly for the standalone read below.
  static const NfcChipReader _nfcReader = ThirdFactorNfc();

  VerificationResult? _result;
  bool _running = false;
  String? _nfcMessage;

  @override
  void dispose() {
    _urlController.dispose();
    super.dispose();
  }

  Future<void> _startVerification() async {
    final url = _urlController.text.trim();
    if (url.isEmpty) {
      ScaffoldMessenger.of(context).showSnackBar(
        const SnackBar(content: Text('Paste a hosted session URL first.')),
      );
      return;
    }

    setState(() => _running = true);

    final result = await ThirdFactor.verify(
      context,
      url: url,
      options: VerifyOptions(
        title: 'Verify your identity',
        onEvent: (event) => debugPrint('TF event: $event'),
      ),
      nfcReader: _nfcReader,
    );

    if (!mounted) return;
    setState(() {
      _result = result;
      _running = false;
    });
  }

  // Demonstrates the standalone NFC reader. In a real app the MRZ fields come
  // from the OCR / doc-capture step; hard-coded here for illustration. Requires
  // a physical NFC device and the platform setup in the README.
  Future<void> _readNfc() async {
    setState(() => _nfcMessage = null);
    if (!await _nfcReader.isAvailable()) {
      if (!mounted) return;
      setState(() => _nfcMessage = 'NFC is not available on this device.');
      return;
    }
    setState(() => _running = true);
    try {
      final chip = await _nfcReader.read(
        documentNumber: 'X1234567',
        dateOfBirth: '900101',
        dateOfExpiry: '300101',
      );
      if (!mounted) return;
      // Send chip.toBridgeData() to your backend for passive authentication.
      setState(() =>
          _nfcMessage = 'Read OK: ${chip.toBridgeData().keys.join(', ')}');
    } on NfcException catch (e) {
      if (!mounted) return;
      setState(() => _nfcMessage = 'Failed (${e.code.wire}): ${e.message}');
    } finally {
      if (mounted) setState(() => _running = false);
    }
  }

  @override
  Widget build(BuildContext context) {
    final result = _result;
    return Scaffold(
      appBar: AppBar(title: const Text('ThirdFactor KYC Example')),
      body: Padding(
        padding: const EdgeInsets.all(20),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.stretch,
          children: [
            const Text(
              'Create a session on your backend (POST /v3/session/) and paste '
              'its "url" here.',
            ),
            const SizedBox(height: 16),
            TextField(
              controller: _urlController,
              keyboardType: TextInputType.url,
              decoration: const InputDecoration(
                labelText: 'Hosted session URL',
                hintText: 'https://kyc.acme.com/verify/<token>',
                border: OutlineInputBorder(),
              ),
            ),
            const SizedBox(height: 16),
            FilledButton.icon(
              onPressed: _running ? null : _startVerification,
              icon: const Icon(Icons.verified_user_outlined),
              label: Text(_running ? 'Running…' : 'Start verification'),
            ),
            const SizedBox(height: 12),
            OutlinedButton.icon(
              onPressed: _running ? null : _readNfc,
              icon: const Icon(Icons.nfc),
              label: const Text('Read passport NFC (standalone)'),
            ),
            const SizedBox(height: 24),
            if (result != null) _ResultCard(result: result),
            if (_nfcMessage != null) ...[
              const SizedBox(height: 16),
              Card(
                child: Padding(
                  padding: const EdgeInsets.all(16),
                  child: Text('NFC: $_nfcMessage'),
                ),
              ),
            ],
          ],
        ),
      ),
    );
  }
}

class _ResultCard extends StatelessWidget {
  const _ResultCard({required this.result});

  final VerificationResult result;

  @override
  Widget build(BuildContext context) {
    return Card(
      child: Padding(
        padding: const EdgeInsets.all(16),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            Text('Status: ${result.status.name}',
                style: Theme.of(context).textTheme.titleMedium),
            if (result.rawStatus != null)
              Text('Raw status: ${result.rawStatus}'),
            if (result.sessionId != null)
              Text('Session id: ${result.sessionId}'),
            if (result.error != null)
              Text('Error: ${result.error!.code} — ${result.error!.message}'),
            const SizedBox(height: 8),
            const Text(
              'Reminder: confirm the decision server-side via the signed webhook '
              'or GET /v3/session/<id>/decision/ before trusting it.',
              style: TextStyle(fontStyle: FontStyle.italic, fontSize: 12),
            ),
          ],
        ),
      ),
    );
  }
}
0
likes
110
points
10
downloads

Documentation

API reference

Publisher

unverified uploader

Weekly Downloads

ThirdFactor / Obsidian KYC — Flutter client SDK. Opens the hosted verification flow in a WebView and returns one normalized result. Native ePassport/eID NFC reading plugs in via the thirdfactor_kyc_nfc companion.

Repository (GitHub)
View/report issues

License

unknown (license)

Dependencies

flutter, webview_flutter, webview_flutter_android, webview_flutter_wkwebview

More

Packages that depend on thirdfactor_kyc