Deleting a device
Users might need to delete an MFA device if it’s lost or replaced. To do so, first authenticate with the device, then use thedeleteUserDevice function.
- React
- React Native
- Flutter
Delete a TOTP device with TOTP code:Delete a TOTP device with recovery code:
Copy
Ask AI
import { useMfa } from '@dynamic-labs/sdk-react-core';
const { authenticateDevice, deleteUserDevice } = useMfa();
const deleteDevice = async (deviceId: string, code: string) => {
// First, create a single-use MFA token for the device
const mfaAuthToken = await authenticateDevice({
code,
deviceId,
createMfaToken: { singleUse: true }
});
// Then, delete the device using the token
await deleteUserDevice(deviceId, mfaAuthToken);
};
Copy
Ask AI
import { useMfa } from '@dynamic-labs/sdk-react-core';
const { authenticateRecoveryCode, deleteUserDevice } = useMfa();
const deleteDevice = async (deviceId: string, code: string) => {
// First, create a single-use MFA token for the device
const mfaAuthToken = await authenticateRecoveryCode({
code,
createMfaToken: { singleUse: true }
});
// Then, delete the device using the token
await deleteUserDevice(deviceId, mfaAuthToken);
};
Delete a TOTP device with TOTP code:Delete a TOTP device with recovery code:Delete a passkey:
Copy
Ask AI
import React, { useState } from 'react';
import { Alert, View, TextInput, Button } from 'react-native';
import { useDynamic } from './path-to-your-client';
export function DeleteMfaDevice({ deviceId }: { deviceId: string }) {
const client = useDynamic();
const [code, setCode] = useState('');
const [loading, setLoading] = useState(false);
const handleDeleteDevice = async () => {
if (!code.trim()) {
Alert.alert('Error', 'Please enter the verification code');
return;
}
try {
setLoading(true);
// First, authenticate with the device to create MFA token
const mfaAuthToken = await client.mfa.authenticateDevice({
code,
deviceId,
createMfaToken: { singleUse: true }
});
if (!mfaAuthToken) {
Alert.alert('Error', 'Failed to authenticate device');
return;
}
// Then, delete the device using the token
await client.mfa.deleteUserDevice(deviceId, mfaAuthToken);
Alert.alert('Success', 'MFA device deleted successfully');
} catch (error) {
console.error('Failed to delete MFA device:', error);
Alert.alert('Error', 'Failed to delete MFA device');
} finally {
setLoading(false);
}
};
return (
<View>
<TextInput
placeholder="Enter 6-digit code"
value={code}
onChangeText={setCode}
keyboardType="numeric"
maxLength={6}
/>
<Button
title="Delete Device"
onPress={handleDeleteDevice}
disabled={loading}
/>
</View>
);
}
Copy
Ask AI
import React, { useState } from 'react';
import { Alert, View, TextInput, Button } from 'react-native';
import { useDynamic } from './path-to-your-client';
export function DeleteMfaDeviceWithRecovery({ deviceId }: { deviceId: string }) {
const client = useDynamic();
const [recoveryCode, setRecoveryCode] = useState('');
const [loading, setLoading] = useState(false);
const handleDeleteDevice = async () => {
if (!recoveryCode.trim()) {
Alert.alert('Error', 'Please enter the recovery code');
return;
}
try {
setLoading(true);
// First, authenticate with recovery code to create MFA token
const mfaAuthToken = await client.mfa.authenticateRecoveryCode({
code: recoveryCode,
createMfaToken: { singleUse: true }
});
if (!mfaAuthToken) {
Alert.alert('Error', 'Failed to authenticate recovery code');
return;
}
// Then, delete the device using the token
await client.mfa.deleteUserDevice(deviceId, mfaAuthToken);
Alert.alert('Success', 'MFA device deleted successfully');
} catch (error) {
console.error('Failed to delete MFA device:', error);
Alert.alert('Error', 'Failed to delete MFA device');
} finally {
setLoading(false);
}
};
return (
<View>
<TextInput
placeholder="Enter recovery code"
value={recoveryCode}
onChangeText={setRecoveryCode}
/>
<Button
title="Delete Device"
onPress={handleDeleteDevice}
disabled={loading}
/>
</View>
);
}
Copy
Ask AI
import React, { useState } from 'react';
import { Alert, View, Button } from 'react-native';
import { dynamicClient } from './path-to-your-client';
export function DeletePasskey({ passkeyId }: { passkeyId: string }) {
const [loading, setLoading] = useState(false);
const handleDeletePasskey = async () => {
try {
setLoading(true);
await dynamicClient.passkeys.delete({ passkeyId });
Alert.alert('Success', 'Passkey deleted successfully');
} catch (error) {
console.error('Failed to delete passkey:', error);
Alert.alert('Error', 'Failed to delete passkey');
} finally {
setLoading(false);
}
};
return (
<View>
<Button
title="Delete Passkey"
onPress={handleDeletePasskey}
disabled={loading}
/>
</View>
);
}
Delete a TOTP device with TOTP code:Delete a TOTP device with recovery code:
Copy
Ask AI
Future<void> _handleDeleteDevice(MfaDevice device) async {
if (device.id == null) return;
final code = await _showCodeInputDialog(
title: 'Authenticate device',
message:
'Enter the TOTP code from your authenticator app to delete this MFA device',
);
if (code == null || code.isEmpty) return;
try {
final mfaAuthToken = await DynamicSDK.instance.mfa.authenticateDevice(params: MfaAuthenticateDevice(code: code, deviceId: device.id, createMfaToken: const MfaCreateToken(singleUse: true))
);
if (mfaAuthToken == null || mfaAuthToken.isEmpty) {
if (mounted) {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
content: Text('Failed to authenticate device'),
backgroundColor: Colors.red,
),
);
}
return;
}
await DynamicSDK.instance.mfa.deleteUserDevice(device.id!, mfaAuthToken);
}catch(e){}
}
Future<String?> _showCodeInputDialog({
required String title,
required String message,
}) async {
final codeController = TextEditingController();
return showDialog<String>(
context: context,
builder: (context) => AlertDialog(
title: Text(title),
content: Column(
mainAxisSize: MainAxisSize.min,
children: [
Text(message),
const SizedBox(height: Spacing.space16),
TextField(
controller: codeController,
keyboardType: TextInputType.number,
decoration: const InputDecoration(
labelText: 'TOTP Code',
hintText: 'Enter 6-digit code',
),
maxLength: 6,
),
],
),
actions: [
TextButton(
onPressed: () => Navigator.of(context).pop(),
child: const Text('Cancel'),
),
TextButton(
onPressed: () => Navigator.of(context).pop(codeController.text),
child: const Text('OK'),
),
],
),
);
}
Copy
Ask AI
Future<void> _handleDeleteDevice(MfaDevice device, String recoveryCode) async {
try {
final mfaAuthToken = await DynamicSDK.instance.mfa.authenticateRecoveryCode(code: MfaAuthenticateRecoveryCode(code: recoveryCode, createMfaToken: const MfaCreateToken(singleUse: true))
);
if (mfaAuthToken == null || mfaAuthToken.isEmpty) {
if (mounted) {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
content: Text('Failed to authenticate device'),
backgroundColor: Colors.red,
),
);
}
return;
}
await DynamicSDK.instance.mfa.deleteUserDevice(device.id!, mfaAuthToken);
} catch(e){}
}
Admin Reset
If a user loses all their devices and recovery codes, an admin can reset their MFA from the Dynamic dashboard.- Go to the Users page in the Dynamic Dashboard.
- Find the user and open their detail panel.
- In the Security section, click Reset MFA.
- Confirm the action.