@owl-eyes/react-native-nfc
v1.0.8
Published
React Native NFC passport reading SDK for Owl Eyes identity verification
Downloads
853
Maintainers
Readme
@owl-eyes/react-native-nfc
React Native NFC passport reading SDK for Owl Eyes identity verification.
Cross-platform bridge to native Android and iOS NFC passport reading libraries.
Features
- 🔐 BAC/PACE Authentication - Automatic protocol selection
- 📖 Data Group Reading - DG1-DG16, SOD, COM
- ✅ Passive Authentication - SOD signature verification
- 🛡️ Active Authentication - Chip authenticity verification
- 🔒 Chip Authentication - Clone detection
- 📱 Cross-Platform - iOS 14+ and Android 7+
- ⚡ React Hooks - Easy integration with React Native apps
- 📊 Progress Events - Real-time progress updates
- 🎯 TypeScript - Full type safety
Installation
# Using npm
npm install @owl-eyes/react-native-nfc
# Using yarn
yarn add @owl-eyes/react-native-nfciOS Setup
- Add NFC entitlements to your app:
<!-- ios/YourApp/YourApp.entitlements -->
<key>com.apple.developer.nfc.readersession.iso7816.select-identifiers</key>
<array>
<string>A0000002471001</string>
</array>- Add NFC usage description to Info.plist:
<key>NFCReaderUsageDescription</key>
<string>We need NFC access to read your passport chip for identity verification.</string>- Install pods:
cd ios && pod installAndroid Setup
- Add NFC permissions to AndroidManifest.xml:
<uses-permission android:name="android.permission.NFC" />
<uses-feature android:name="android.hardware.nfc" android:required="true" />- The SDK automatically enables NFC foreground dispatch.
Quick Start
import { OwlEyesNFC } from '@owl-eyes/react-native-nfc';
// Check NFC availability
const isSupported = await OwlEyesNFC.isNFCSupported();
const isEnabled = await OwlEyesNFC.isNFCEnabled();
if (!isEnabled) {
await OwlEyesNFC.openNFCSettings();
}
// Read passport
const result = await OwlEyesNFC.readPassport({
documentNumber: '123456789',
dateOfBirth: '1990-01-15', // YYYY-MM-DD
dateOfExpiry: '2028-01-15',
includeImages: true,
});
if (result.success) {
console.log('Name:', result.data?.mrz.firstName);
console.log('Passive Auth:', result.data?.passiveAuthPassed);
console.log('Active Auth:', result.data?.activeAuthPassed);
}Using React Hooks
useNFCReader
Full-featured hook for managing NFC reader state:
import { useNFCReader } from '@owl-eyes/react-native-nfc';
function PassportReader() {
const {
isAvailable,
isEnabled,
isReading,
progress,
result,
readPassport,
openSettings,
} = useNFCReader();
if (!isAvailable) {
return <Text>NFC not available on this device</Text>;
}
if (!isEnabled) {
return (
<Button title="Enable NFC" onPress={openSettings} />
);
}
return (
<View>
<Button
title="Scan Passport"
disabled={isReading}
onPress={() => readPassport({
documentNumber: '123456789',
dateOfBirth: '1990-01-15',
dateOfExpiry: '2028-01-15',
})}
/>
{isReading && (
<View>
<ProgressBar progress={progress?.progress ?? 0} />
<Text>{progress?.message}</Text>
</View>
)}
{result?.success && (
<Text>Name: {result.data?.mrz.firstName}</Text>
)}
</View>
);
}usePassportRead
Simplified hook focused on the read operation:
import { usePassportRead } from '@owl-eyes/react-native-nfc';
function PassportScanner() {
const {
state, // 'idle' | 'waiting' | 'reading' | 'complete' | 'error'
progress, // 0-100
message,
passport,
error,
read,
cancel,
reset,
} = usePassportRead();
// ... render based on state
}useNFCState
Simple hook for monitoring NFC availability:
import { useNFCState } from '@owl-eyes/react-native-nfc';
function App() {
const { availability, isReady, isLoading } = useNFCState();
if (isLoading) {
return <ActivityIndicator />;
}
if (!isReady) {
return <NFCNotAvailableScreen />;
}
return <PassportReaderScreen />;
}API Reference
OwlEyesNFC
Methods
| Method | Description |
|--------|-------------|
| isNFCSupported() | Check if device has NFC hardware |
| isNFCEnabled() | Check if NFC is enabled |
| getCapabilities() | Get detailed NFC capabilities |
| openNFCSettings() | Open device NFC settings |
| readPassport(options) | Read passport via NFC |
| cancelRead() | Cancel ongoing read |
| fetchCertificates(countryCode?) | Pre-fetch CSCA certificates |
| hasCertificates() | Check if certificates are loaded |
| clearCertificates() | Clear cached certificates |
NFCReadOptions
interface NFCReadOptions {
documentNumber: string; // Passport number
dateOfBirth: string; // YYYY-MM-DD
dateOfExpiry: string; // YYYY-MM-DD
includeImages?: boolean; // Include face/signature images
performActiveAuth?: boolean; // Attempt Active Authentication
performChipAuth?: boolean; // Attempt Chip Authentication
timeout?: number; // Timeout in milliseconds
dataGroups?: DataGroupSelection[]; // Specific data groups to read
}NFCReadResult
interface NFCReadResult {
success: boolean;
data?: {
mrz: MRZData;
faceImage?: string; // Base64
signatureImage?: string; // Base64
passiveAuthPassed: boolean;
activeAuthPassed?: boolean;
chipAuthPassed?: boolean;
documentInfo: DocumentInfo;
};
error?: NFCError;
readTimeMs?: number;
protocolUsed?: 'BAC' | 'PACE';
}Event Emitter
Subscribe to NFC events:
import { NFCEventEmitter } from '@owl-eyes/react-native-nfc';
// NFC state changes (Android)
const unsubscribe1 = NFCEventEmitter.addStateChangeListener((event) => {
console.log('NFC enabled:', event.enabled);
});
// Progress updates
const unsubscribe2 = NFCEventEmitter.addProgressListener((progress) => {
console.log(`${progress.stage}: ${progress.progress}%`);
});
// Tag detected
const unsubscribe3 = NFCEventEmitter.addTagDetectedListener((event) => {
console.log('Tag detected:', event.isISODEP);
});
// Clean up
unsubscribe1();
unsubscribe2();
unsubscribe3();Utility Functions
MRZ Helpers
import {
formatDateForMRZ,
parseDateFromMRZ,
validateMRZInput,
sanitizeDocumentNumber,
} from '@owl-eyes/react-native-nfc';
// Format date for BAC/PACE key
const dob = formatDateForMRZ('1990-01-15'); // '900115'
// Parse MRZ date
const date = parseDateFromMRZ('900115'); // Date object
// Validate inputs
const error = validateMRZInput('123456789', '1990-01-15', '2028-01-15');
if (error) {
console.error(error);
}
// Clean document number
const docNum = sanitizeDocumentNumber('AB<123456<'); // 'AB123456'Error Handling
import { NFC_ERROR_CODES } from '@owl-eyes/react-native-nfc';
const result = await OwlEyesNFC.readPassport(options);
if (!result.success) {
switch (result.error?.code) {
case NFC_ERROR_CODES.TAG_LOST:
// Ask user to hold steady
break;
case NFC_ERROR_CODES.BAC_FAILED:
// Check document details
break;
case NFC_ERROR_CODES.PASSIVE_AUTH_FAILED:
// Document may be tampered
break;
}
}Testing
Device Requirements
- Android: Any device with NFC (API 24+)
- iOS: iPhone 7 or later (iOS 14+)
Testing Guide
- Use real passports with NFC chips for testing
- Test both BAC-only and PACE passports
- Test expired passports (chips still work)
- Test with various countries' passports
See Testing Documentation for detailed testing procedures.
Troubleshooting
Common Issues
"Tag lost" errors
- Hold the device steady against the passport
- Try different positioning (passport photo page)
- Remove phone case if thick
BAC authentication fails
- Verify document number, DOB, and expiry are correct
- Check for OCR errors in MRZ reading
- Some documents use "filler" characters (<) - try without them
NFC not detected
- Ensure NFC is enabled in device settings
- Check that the passport has an NFC chip (look for the chip symbol)
- Try positioning the phone differently
License
MIT
