Skip to content

pushpender-singh-ap/react-native-otp-verify

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

11 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

@pushpendersingh/react-native-otp-verify

npm [License: MIT]

Automatic SMS OTP verification for React Native Android apps using Google's SMS Retriever and User Consent APIs β€” zero runtime SMS permissions required.

Key points: Zero permissions β€’ Google Play approved β€’ Easy to integrate β€’ TypeScript support


Table of Contents


✨ Features

  • πŸ” Two verification methods: Automatic (silent) and Consent-based (with user approval)
  • 🚫 Zero permissions: No READ_SMS or RECEIVE_SMS permissions needed
  • βœ… Google Play approved: Uses official Google Play Services APIs
  • 🎯 Easy to use: Simple API with TypeScript support
  • πŸ“± Cross-platform support: Android (fully functional) and iOS (graceful error handling)
  • πŸ”„ Event-driven: Listen for SMS events with modern EventEmitter pattern
  • πŸ› οΈ Built with New Architecture: Supports React Native's new architecture (TurboModules)
  • πŸ”’ Thread-Safe: Concurrent-safe receiver management with locks and atomic operations
  • πŸ“Š Enhanced Logging: Comprehensive debug logging for easier troubleshooting

πŸ“¦ Installation

npm install @pushpendersingh/react-native-otp-verify

or

yarn add @pushpendersingh/react-native-otp-verify

Requirements

  • React Native >= 0.76
  • Android API Level >= 24
  • Google Play Services
  • Expo prebuild is supported.

πŸš€ Quick Start

import {
  startSmsRetriever,
  addSmsListener,
  getAppSignature,
  extractOtp,
} from '@pushpendersingh/react-native-otp-verify';

// Get app signature (needed for SMS format)
const signature = await getAppSignature();
console.log('App Signature:', signature);

// Start listening for SMS
await startSmsRetriever();

// Add listener for incoming SMS
const removeListener = addSmsListener((message) => {
  if (message.status === 'success' && message.message) {
    const otp = extractOtp(message.message);
    console.log('OTP:', otp);
  }
});

// Clean up when done
removeListener();

πŸ“š API Reference

Two Verification Methods

This library provides two different approaches for SMS OTP verification:

Method User Action SMS Format Use Case
SMS Retriever None (Automatic) Requires app hash Best for your own backend
SMS User Consent User taps "Allow" Any format Works with any SMS sender

1️⃣ SMS Retriever API (Automatic)

startSmsRetriever()

Starts the SMS Retriever API to automatically capture SMS messages containing your app's signature.

  • Returns: Promise<string>
  • Throws: Error if failed to start
  • Duration: Listens for up to 5 minutes
import { startSmsRetriever } from '@pushpendersingh/react-native-otp-verify';

try {
  await startSmsRetriever();
  console.log('SMS Retriever started');
} catch (error) {
  console.error('Failed to start:', error);
}

getAppSignature()

Gets your app's 11-character hash signature that must be included in SMS messages.

  • Returns: Promise<string> - The app signature (e.g., FA+9qCX9VSu)
  • Throws: Error if signature cannot be generated
import { getAppSignature } from '@pushpendersingh/react-native-otp-verify';

try {
  const signature = await getAppSignature();
  console.log('App Signature:', signature);
  // Send this signature to your backend
} catch (error) {
  console.error('Failed to get signature:', error);
}

Important: Send this signature to your backend so it can be included in SMS messages.


addSmsListener(callback)

Adds a listener for incoming SMS events.

  • Parameters:
    • callback: (message: SmsMessage) => void - Function called when SMS is received
  • Returns: () => void - Function to remove the listener

SmsMessage Interface:

interface SmsMessage {
  message: string | null;      // The full SMS message content
  status: 'success' | 'timeout' | 'error';
  senderAddress?: string;      // Sender's phone number (if available)
}

Example:

import { addSmsListener } from '@pushpendersingh/react-native-otp-verify';

const removeListener = addSmsListener((message) => {
  console.log('SMS Status:', message.status);
  
  if (message.status === 'success') {
    console.log('SMS:', message.message);
    console.log('From:', message.senderAddress);
  } else if (message.status === 'timeout') {
    console.log('SMS Retriever timed out after 5 minutes');
  } else if (message.status === 'error') {
    console.error('SMS Retriever error');
  }
});

// Don't forget to clean up
removeListener();

removeSmsListener()

Removes the SMS receiver and stops listening for messages.

  • Returns: Promise<string>
import { removeSmsListener } from '@pushpendersingh/react-native-otp-verify';

try {
  await removeSmsListener();
  console.log('SMS Listener removed');
} catch (error) {
  console.error('Failed to remove listener:', error);
}

extractOtp(message, pattern?)

Extracts OTP code from SMS message using regex pattern.

  • Parameters:
    • message: string - The SMS message text
    • pattern?: RegExp - Custom regex pattern (optional)
  • Returns: string | null - The extracted OTP or null if not found
  • Default Pattern: Matches 4-8 digit codes

Example:

import { extractOtp } from '@pushpendersingh/react-native-otp-verify';

const sms = "Your OTP is: 123456\\n\\nFA+9qCX9VSu";
const otp = extractOtp(sms);
console.log('OTP:', otp); // "123456"

// Custom pattern for alphanumeric codes
const customPattern = /[A-Z0-9]{6}/;
const code = extractOtp("Your code: ABC123", customPattern);
console.log('Code:', code); // "ABC123"

2️⃣ SMS User Consent API (With User Approval)

requestPhoneNumber()

Starts the SMS User Consent API which shows a consent dialog when SMS arrives.

  • Returns: Promise<string>
  • Throws: Error if failed to start

How it works:

  1. Call this function to start listening
  2. When SMS arrives, Google shows a consent dialog
  3. User taps "Allow" or "Deny"
  4. SMS is delivered through addSmsListener callback

Example:

import { requestPhoneNumber, addSmsListener, extractOtp } from '@pushpendersingh/react-native-otp-verify';

// Add listener first
const removeListener = addSmsListener((message) => {
  if (message.status === 'success' && message.message) {
    console.log('User approved SMS:', message.message);
    const otp = extractOtp(message.message);
    console.log('OTP:', otp);
  } else if (message.status === 'error') {
    console.log('User denied consent');
  }
});

// Start SMS User Consent
try {
  await requestPhoneNumber();
  console.log('Waiting for SMS... User will see consent dialog');
} catch (error) {
  console.error('Failed to start consent:', error);
}

// Clean up
removeListener();

πŸ“‹ Complete Examples

Example 1: SMS Retriever (Automatic)

import React, { useEffect, useState } from 'react';
import { View, Text, Button, Alert } from 'react-native';
import {
  startSmsRetriever,
  addSmsListener,
  getAppSignature,
  extractOtp,
  removeSmsListener,
} from '@pushpendersingh/react-native-otp-verify';

export default function OtpScreen() {
  const [otp, setOtp] = useState('');
  const [signature, setSignature] = useState('');

  useEffect(() => {
    // Get app signature on mount
    getAppSignature().then(setSignature);

    // Add SMS listener
    const removeListener = addSmsListener((message) => {
      if (message.status === 'success' && message.message) {
        const code = extractOtp(message.message);
        if (code) {
          setOtp(code);
          Alert.alert('OTP Received', `Code: ${code}`);
        }
      } else if (message.status === 'timeout') {
        Alert.alert('Timeout', 'No SMS received in 5 minutes');
      }
    });

    // Cleanup on unmount
    return () => {
      removeListener();
      removeSmsListener();
    };
  }, []);

  const handleStartListening = async () => {
    try {
      await startSmsRetriever();
      Alert.alert('Listening', 'Waiting for OTP SMS...');
    } catch (error) {
      Alert.alert('Error', error.message);
    }
  };

  return (
    <View style={{ padding: 20 }}>
      <Text>App Signature: {signature}</Text>
      <Text>OTP: {otp}</Text>
      <Button title="Start Listening" onPress={handleStartListening} />
    </View>
  );
}

SMS Format for your backend:

<#> Your OTP is: 123456

FA+9qCX9VSu

Example 2: SMS User Consent

import React, { useEffect, useState } from 'react';
import { View, Text, Button, Alert } from 'react-native';
import {
  requestPhoneNumber,
  addSmsListener,
  extractOtp,
} from '@pushpendersingh/react-native-otp-verify';

export default function ConsentOtpScreen() {
  const [otp, setOtp] = useState('');

  useEffect(() => {
    const removeListener = addSmsListener((message) => {
      if (message.status === 'success' && message.message) {
        const code = extractOtp(message.message);
        if (code) {
          setOtp(code);
          Alert.alert('OTP Received', `Code: ${code}`);
        }
      } else if (message.status === 'error') {
        Alert.alert('Denied', 'You denied SMS access');
      }
    });

    return () => removeListener();
  }, []);

  const handleRequestConsent = async () => {
    try {
      await requestPhoneNumber();
      Alert.alert('Waiting for SMS', 'You will see a consent dialog when SMS arrives');
    } catch (error) {
      Alert.alert('Error', error.message);
    }
  };

  return (
    <View style={{ padding: 20 }}>
      <Text>OTP: {otp}</Text>
      <Button title="Request SMS Consent" onPress={handleRequestConsent} />
    </View>
  );
}

Works with any SMS format:

Your verification code is 123456

πŸ”§ Backend Integration

SMS Format for SMS Retriever API

Your backend must send SMS in this exact format:

<#> Your message here
OTP: 123456

YOUR_APP_SIGNATURE

Rules:

  • Must start with <#>
  • Message can be up to 140 bytes
  • Must end with your 11-character app signature
  • One blank line before signature

Example: Node.js Backend

const signature = 'FA+9qCX9VSu'; // Get this from getAppSignature()
const otp = '123456';

const sms = `<#> Your OTP is: ${otp}

${signature}`;

// Send SMS using your SMS provider (Twilio, AWS SNS, etc.)
await sendSMS(phoneNumber, sms);

πŸ†š When to Use Which Method

Use SMS Retriever when

  • βœ… You control the backend/SMS format
  • βœ… You want fully automatic verification
  • βœ… You want the best user experience (no interaction)

Use SMS User Consent when

  • βœ… You can't control SMS format (3rd party service)
  • βœ… You want to give users explicit control
  • βœ… SMS doesn't have your app signature

πŸ›‘οΈ Permissions

None required! πŸŽ‰

Both APIs use Google Play Services and require zero permissions.

<!-- AndroidManifest.xml - NO SMS permissions needed! -->
<manifest>
  <!-- No READ_SMS -->
  <!-- No RECEIVE_SMS -->
</manifest>

🍎 iOS Support

iOS is supported with graceful error handling. The library includes native iOS implementation that:

  • βœ… Links properly without build errors
  • βœ… Returns clear error messages when methods are called
  • βœ… Follows proper TurboModule protocol
  • ⚠️ Does not provide OTP verification functionality (Android-only feature)

All methods will reject with error code PLATFORM_NOT_SUPPORTED and message explaining that the feature is Android-only.

Example:

try {
  await startSmsRetriever();
} catch (error) {
  // On iOS: "@pushpendersingh/react-native-otp-verify package only supports Android."
  console.log(error.message);
}

Best Practice:

import { Platform } from 'react-native';

if (Platform.OS === 'android') {
  // Use OTP verification on Android only
  await startSmsRetriever();
}

πŸ› Troubleshooting

SMS not being captured

  1. Check app signature: Make sure backend is using correct signature from getAppSignature()
  2. SMS format: Verify SMS follows exact format with <#> and signature
  3. Timeout: SMS Retriever only listens for 5 minutes
  4. Google Play Services: Make sure device has Google Play Services installed

Consent dialog not showing

  1. Check SMS arrives: Dialog only shows when SMS actually arrives
  2. Background app: Make sure app is in foreground when SMS arrives

Build errors

cd android && ./gradlew clean
cd .. && npx react-native run-android

πŸ“– TypeScript Support

Full TypeScript definitions included:

import {
  startSmsRetriever,
  getAppSignature,
  requestPhoneNumber,
  addSmsListener,
  removeSmsListener,
  extractOtp,
  SmsMessage,
} from '@pushpendersingh/react-native-otp-verify';

// All functions are fully typed
const signature: Promise<string> = getAppSignature();

🀝 Contributing

See CONTRIBUTING.md for development workflow and guidelines.


πŸ“„ License

MIT


πŸ™ Credits


πŸ“š Resources

About

Automatic OTP verification for React Native. Zero-permission SMS verification using Google's SMS Retriever API on Android.

Resources

License

Code of conduct

Contributing

Stars

Watchers

Forks