NOTE: This library is still in early development. Please open an issue if you encounter any problems or have suggestions.
A lightweight React Native module that helps you route otpauth://
links to
third-party password managers such as 1Password, Bitwarden, Authy, LastPass,
Dashlane, Microsoft Authenticator, or fall back to Apple Passwords on iOS.
yarn add react-native-otp-auth-link
iOS restricts which custom URL schemes can be queried via Linking.canOpenURL
.
If you don’t whitelist them, your app cannot detect or open password managers.
Add the following block to your ios/<AppName>/Info.plist
:
<key>LSApplicationQueriesSchemes</key>
<array>
<string>onepassword</string>
<string>bitwarden</string>
<string>authy</string>
<string>lastpass</string>
<string>dashlane</string>
<string>msauthv2</string>
</array>
👉 No changes are required for Apple Passwords (iOS handles otpauth:// natively).
Since Android 11 (API 30), apps must declare which external packages they can query. If you don’t, your app cannot detect or open password managers.
Add the following block to your android/app/src/main/AndroidManifest.xml
:
<manifest ...>
<queries>
<intent>
<action android:name="android.intent.action.VIEW" />
<data android:scheme="onepassword" />
</intent>
<intent>
<action android:name="android.intent.action.VIEW" />
<data android:scheme="bitwarden" />
</intent>
<intent>
<action android:name="android.intent.action.VIEW" />
<data android:scheme="authy" />
</intent>
<intent>
<action android:name="android.intent.action.VIEW" />
<data android:scheme="lastpass" />
</intent>
<intent>
<action android:name="android.intent.action.VIEW" />
<data android:scheme="dashlane" />
</intent>
<intent>
<action android:name="android.intent.action.VIEW" />
<data android:scheme="msauthv2" />
</intent>
<intent>
<action android:name="android.intent.action.VIEW" />
<data android:scheme="otpauth" />
</intent>
</queries>
<application ...>
...
</application>
</manifest>
If you use Expo, you'll first need to crate a custom config plugin to modify the AndroidManifest.xml.
// plugins/withAndroidPlugin.ts
import { withAndroidManifest, ConfigPlugin } from "expo/config-plugins";
const withAndroidPlugin: ConfigPlugin = (config) => {
return withAndroidManifest(config, (config) => {
const schemes = [
"msauthv2",
"onepassword",
"lastpass",
"dashlane",
"authy",
"otpauth",
];
config.modResults.manifest.queries = [
{
intent: schemes.map((scheme) => ({
action: [{ $: { "android:name": "android.intent.action.VIEW" } }],
data: [{ $: { "android:scheme": scheme } }],
})),
},
];
return config;
});
};
export default withAndroidPlugin;
Then, in your app.config.js
, include the plugin with the rest of your config
and the iOS Info.plist
changes:
export default {
ios: {
infoPlist: {
LSApplicationQueriesSchemes: [
"onepassword",
"bitwarden",
"authy",
"lastpass",
"dashlane",
"msauthv2",
],
},
...
},
plugins: ["./plugins/withAndroidPlugin", ...],
};
NOTE: React Native does not allow you to open modals from outside the render tree. To properly support the manager picker on Android, use the
useOtpManager
hook.
import { useOtpManager } from "react-native-otp-auth-link";
const { openManager, pickerData, hidePicker } = useOtpManager();
return (
<View>
<Button onPress={() => openManager('otpauth://...')} />
{pickerData && (
<ManagerPicker
url={pickerData.url}
managers={pickerData.managers}
visible={true}
onClose={hidePicker}
/>
)}
</View>
);
Otherwise, you can use the openOtpManager
function directly.
import { openOtpManager } from "react-native-otp-auth-link";
const url =
"otpauth://totp/Example:alice@example.com?secret=ABC123&issuer=Example";
await openOtpManager(url);
Contributions are welcome! Please open an issue or submit a pull request.
MIT © Dylan Duunk