Skip to content

MULERx/expo-otp-autofill

Repository files navigation

expo-otp-autofill

A native Expo wrapper for Android's official Google SMS Retriever API. This library allows your React Native / Expo application to automatically detect and auto-fill incoming OTP SMS messages with ZERO Android permissions requested from the user.

npm version Platform License: MIT


🚀 Features

Feature Description
Zero Permissions No need to ask the user for dangerous RECEIVE_SMS or READ_SMS permissions. Google Play Store natively approves this exact implementation.
Silent Intercept Google Play Services natively intercepts only the SMS meant for your app based on the unique 11-char App Hash.
useOtpAutoFill Hook Simple plug-and-play React hook with auto-parsing logic.
Continuous Listening Uniquely allows intercepting multiple consecutive OTP messages by instantly resetting the background listener after every read.
App Hash Generator Instantly generate the exact 11-character app hash Google requires (getAppHashAsync()) programmatically.

Note: Because this library uses the official Google SMS Retriever API, the server transmitting your OTP messages must append your 11-character App Hash at the very end of the SMS content. Example:

Your verification code is 123456. AB12cd3Efgh


📦 Installation

npx expo install expo-otp-autofill

After installation, ensure you rebuild your Android codebase, as this includes native Google Play Services dependencies:

npx expo prebuild --clean
npx expo run:android

📖 Hook Usage: useOtpAutoFill()

This is the main API you will use inside your components. It will trigger Android to listen for the OTP SMS targeting your app for up to 5 minutes.

import React, { useEffect } from 'react';
import { View, TextInput, Button, Text } from 'react-native';
import { useOtpAutoFill, getAppHashAsync } from 'expo-otp-autofill';

export default function MyLoginScreen() {
  // 1. Hook begins listening automatically on mount and seamlessly resets after an OTP is intercepted
  const { otp, message, clear } = useOtpAutoFill({
    length: 6,         // Optional: Number of digits to extract (default is [4, 8])
    timeout: 30000,    // Optional: How long to keep the `otp` state visible horizontally before clearing (default 30000ms. 0 disables)
  });

  useEffect(() => {
    // Optional: Print your 11-character App Hash so you can configure it on your server!
    getAppHashAsync().then((hash) => console.log('My App Hash is:', hash));
  }, []);

  return (
    <View style={{ flex: 1, justifyContent: 'center', padding: 20 }}>
      {message && <Text style={{ color: 'gray' }}>Captured exact SMS: {message}</Text>}
      
      <TextInput
        value={otp ?? ''}
        placeholder="Waiting for OTP without permissions..."
        style={{ borderWidth: 1, padding: 10, marginVertical: 10, fontSize: 20 }}
      />
      
      <Button title="Manually Clear OTP" onPress={clear} />
    </View>
  );
}

Options

Option Type Default Description
length number or [min, max] [4, 8] Forces regex to only extract digits matching this length constraint.
timeout number 30000 Once an OTP is parsed, automatically clear the state variable to null after this many milliseconds. Pass 0 to disable auto-clearing.

Return Value

Property Type Description
otp string | null The purely extracted numeric code (e.g. "123456")
message string | null The raw complete SMS message including your app hash.
clear () => void Removes the otp and message states from the screen, without killing the background listener. The API will immediately capture the next OTP sent.

📖 Under-the-Hood APIs

If you prefer imperative control instead of Hooks, you can use the core functions explicitly:

startSmsRetrieverAsync()

Initiates 5-minute listening window inside Google Play Services. Returns boolean.

const started = await startSmsRetrieverAsync();

stopSmsRetrieverAsync()

Stops listening and unregisters native Broadcast Receiver. (No-op if already stopped).

stopSmsRetrieverAsync();

getAppHashAsync()

Computes the 11-char hash from your current Keystore. Returns String.

const hash = await getAppHashAsync();

extractOtp(text, options?)

Pure JS function to extract OTP digits out of a larger SMS phrase.

const extracted = extractOtp('Your code is 6451. df3Wz2qP', { length: 4 });
// "6451"

🤝 Need to read ALL messages without a hash?

If you are building an offline app, a budget tracker, or an app that does not control the server sending the SMS, the SMS Retriever API will not work for you.

Instead, use its sister library: expo-sms-listener. It requires the RECEIVE_SMS user permission, but allows you to capture any SMS from any sender, even when your app is completely closed.


License

MIT © MULERx

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors