flutter_digilocker_aadhar_pan

Flutter plugin for seamless DigiLocker Aadhar and PAN verification integration.

Features

  • ✅ Easy integration with DigiLocker API
  • ✅ Automatic token management and state handling
  • ✅ WebView-based secure verification flow
  • ✅ Support for Aadhar and PAN verification
  • ✅ Optional PAN pre-fill functionality
  • ✅ Customizable document selection
  • ✅ Loading indicators and error handling
  • ✅ Clean modal-based UI
  • ✅ Type-safe response handling

Installation

Add this to your package's pubspec.yaml file:

dependencies:
  flutter_digilocker_aadhar_pan: ^1.0.0

Then run:

flutter pub get

Platform Setup

Android

Add internet permission in your android/app/src/main/AndroidManifest.xml:

<uses-permission android:name="android.permission.INTERNET"/>

iOS

Add the following to your ios/Runner/Info.plist:

<key>NSAppTransportSecurity</key>
<dict>
    <key>NSAllowsArbitraryLoads</key>
    <true/>
</dict>

Usage

Basic Example

import 'package:flutter/material.dart';
import 'package:flutter_digilocker_aadhar_pan/flutter_digilocker_aadhar_pan.dart';

class MyApp extends StatefulWidget {
  @override
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  bool _showDigiLocker = false;

  final config = const DigiLockerConfig(
    companyName: 'your-company-name',
    secretToken: 'your-secret-token',
    redirectUrl: 'https://your-redirect-url.com',
    documents: 'aadhaar,pan', // Optional: default is 'aadhaar,pan'
    panName: '',               // Optional: PAN card holder name
    panNo: '',                 // Optional: PAN number
  );

  void _handleSuccess(DigiLockerResponse response) {
    print('DigiLocker Success: ${response.toJson()}');
    
    // Access user data
    print('Name: ${response.data?.name}');
    print('Aadhar: ${response.data?.aadharNo}');
    print('PAN: ${response.data?.panNumber}');
  }

  void _handleError(String error) {
    print('DigiLocker Error: $error');
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: ElevatedButton(
          onPressed: () {
            setState(() {
              _showDigiLocker = true;
            });
          },
          child: Text('Verify with DigiLocker'),
        ),
      ),
      // Show DigiLocker widget when needed
      body: Stack(
        children: [
          // Your main content here
          if (_showDigiLocker)
            DigiLockerWidget(
              config: config,
              onSuccess: _handleSuccess,
              onError: _handleError,
              onClose: () {
                setState(() {
                  _showDigiLocker = false;
                });
              },
            ),
        ],
      ),
    );
  }
}

Configuration

DigiLockerConfig

Property Type Required Default Description
companyName String Yes - Your company name registered with DigiLocker API
secretToken String Yes - Your secret token for API authentication
redirectUrl String Yes - URL to redirect after verification completion
documents String No 'aadhaar,pan' Comma-separated list of documents to fetch
panName String No '' PAN card holder name (leave empty to skip)
panNo String No '' PAN number (leave empty to skip)

DigiLockerWidget Props

Prop Type Required Description
config DigiLockerConfig Yes Configuration object containing API credentials and options
onSuccess Function(DigiLockerResponse) Yes Callback function called when verification is successful
onError Function(String) Yes Callback function called when an error occurs
onClose VoidCallback Yes Callback function to close the widget

Response Data Structure

The onSuccess callback receives a DigiLockerResponse object with the following structure:

DigiLockerResponse {
  int code;              // 200 for success
  bool success;          // true/false
  String status;         // "success" or "error"
  String msg;            // Response message
  DigiLockerData? data;  // User verification data
}

DigiLockerData {
  String? name;
  String? aadharNo;
  String? aadharAddress;
  String? aadharFilename;
  String? aadharImgFilename;
  String? aadharXml;
  String? adharimg;
  String? dob;
  String? gender;
  String? fathername;
  String? house;
  String? locality;
  String? dist;
  String? state;
  String? country;
  String? pincode;
  String? panNumber;
  String? nameOnPan;
  String? panImagePath;
  String? dateTime;
  Map<String, dynamic>? otherDocumentsFiles;
}

Advanced Examples

With PAN Details Pre-filled

final config = const DigiLockerConfig(
  companyName: 'democompany',
  secretToken: 'your-secret-token',
  redirectUrl: 'https://digilocker.meon.co.in/digilocker/thank-you-page',
  documents: 'aadhaar,pan',
  panName: 'JOHN DOE',        // Pre-fill PAN name
  panNo: 'ABCDE1234F',         // Pre-fill PAN number
);

Fetch Only Aadhar

final config = const DigiLockerConfig(
  companyName: 'democompany',
  secretToken: 'your-secret-token',
  redirectUrl: 'https://your-redirect-url.com',
  documents: 'aadhaar',        // Only fetch Aadhar
);

Full Integration Example

import 'package:flutter/material.dart';
import 'package:flutter_digilocker_aadhar_pan/flutter_digilocker_aadhar_pan.dart';

class VerificationScreen extends StatefulWidget {
  @override
  _VerificationScreenState createState() => _VerificationScreenState();
}

class _VerificationScreenState extends State<VerificationScreen> {
  bool _showDigiLocker = false;
  DigiLockerResponse? _response;

  final config = const DigiLockerConfig(
    companyName: 'your-company-name',
    secretToken: 'your-secret-token',
    redirectUrl: 'https://your-redirect-url.com',
  );

  void _handleSuccess(DigiLockerResponse response) {
    setState(() {
      _response = response;
      _showDigiLocker = false;
    });

    // Show success message
    ScaffoldMessenger.of(context).showSnackBar(
      SnackBar(
        content: Text('Verification Successful!'),
        backgroundColor: Colors.green,
      ),
    );

    // Navigate to next screen or save data
    // Navigator.push(...);
  }

  void _handleError(String error) {
    setState(() {
      _showDigiLocker = false;
    });

    // Show error message
    ScaffoldMessenger.of(context).showSnackBar(
      SnackBar(
        content: Text('Error: $error'),
        backgroundColor: Colors.red,
      ),
    );
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('KYC Verification'),
      ),
      body: Stack(
        children: [
          Padding(
            padding: EdgeInsets.all(20),
            child: Column(
              mainAxisAlignment: MainAxisAlignment.center,
              crossAxisAlignment: CrossAxisAlignment.stretch,
              children: [
                if (_response != null) ...[
                  Card(
                    child: Padding(
                      padding: EdgeInsets.all(16),
                      child: Column(
                        crossAxisAlignment: CrossAxisAlignment.start,
                        children: [
                          Text('Name: ${_response!.data?.name ?? 'N/A'}'),
                          SizedBox(height: 8),
                          Text('Aadhar: ${_response!.data?.aadharNo ?? 'N/A'}'),
                          SizedBox(height: 8),
                          Text('PAN: ${_response!.data?.panNumber ?? 'N/A'}'),
                        ],
                      ),
                    ),
                  ),
                  SizedBox(height: 20),
                ],
                ElevatedButton(
                  onPressed: () {
                    setState(() {
                      _showDigiLocker = true;
                    });
                  },
                  child: Text('Start Verification'),
                ),
              ],
            ),
          ),
          if (_showDigiLocker)
            DigiLockerWidget(
              config: config,
              onSuccess: _handleSuccess,
              onError: _handleError,
              onClose: () {
                setState(() {
                  _showDigiLocker = false;
                });
              },
            ),
        ],
      ),
    );
  }
}

Requirements

  • Flutter >= 3.3.0
  • Dart >= 3.6.2
  • Android: minSdkVersion 19
  • iOS: iOS 11.0+

Notes

  • The panName and panNo fields are optional. If you don't provide them, they will default to empty strings
  • Users can provide their own PAN details through your app UI before opening DigiLocker
  • The plugin automatically manages API tokens and state internally
  • All API calls are handled securely within the plugin
  • Make sure to handle errors appropriately in production apps
  • Test thoroughly with your DigiLocker API credentials before deploying

API Endpoints

This plugin uses the following DigiLocker API endpoints:

  1. Get Access Token: POST /get_access_token
  2. Get DigiLocker URL: POST /digi_url
  3. Send Entire Data: POST /v2/send_entire_data

Base URL: https://digilocker.meon.co.in

Troubleshooting

WebView not loading

Make sure you have added the required permissions for Android and iOS as mentioned in the Platform Setup section.

API errors

Verify that your companyName and secretToken are correct and active.

Network errors

Ensure your device/emulator has internet connectivity and can access the DigiLocker API endpoints.

Security

  • Never commit your secretToken to version control
  • Store API credentials securely (use environment variables or secure storage)
  • Always use HTTPS for redirect URLs in production
  • Implement proper error handling and logging

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

License

This project is licensed under the MIT License - see the LICENSE file for details.

Support

For issues and feature requests, please visit our GitHub repository.

Author

Dhananjay Singh - dhananjay@meon.co.in

Changelog

See CHANGELOG.md for a list of changes.

Acknowledgments

  • DigiLocker API by Government of India
  • Flutter team for the amazing framework