---
title: User and Device Management
description: How to manage users and devices with the PingOne Recognize SDK.
component: recognize
page_id: recognize:mobile-sdk:mobile-sdk-user-and-device-management
canonical_url: https://docs.pingidentity.com/recognize/mobile-sdk/mobile-sdk-user-and-device-management.html
llms_txt: https://docs.pingidentity.com/recognize/llms.txt
docs_for_agents: https://developer.pingidentity.com/build-with-ai/docs-for-agents.md
revdate: April 20, 2026
section_ids:
  validate-user-and-device-active: Validate User and Device Active
  android: Android
  ios: iOS
  flutter: Flutter
  react-native: React Native
  user-identifier: User Identifier
  android-2: Android
  ios-2: iOS
  flutter-2: Flutter
  react-native-2: React Native
  device-identifier: Device Identifier
  android-3: Android
  ios-3: iOS
  flutter-3: Flutter
  react-native-3: React Native
  pingone-recognize-sdk-reset: PingOne Recognize SDK Reset
  android-4: Android
  ios-4: iOS
  flutter-4: Flutter
  react-native-4: React Native
  lockout-management: Lockout Management
  android-5: Android
  ios-5: iOS
  flutter-5: Flutter
  react-native-5: React Native
---

# User and Device Management

The PingOne Recognize SDK caches the enrolled user locally on the device.

There are use cases where it is possible to delete the user from Server API and delete the device from Server API . The PingOne Recognize SDK is not notified about such deletions. For this reason, if you try to authenticate a user or a device that has been deleted from Server API, you get an error.

Call `validateUserAndDeviceActive` **before** authenticating to validate that both the user and the device are still active in the PingOne Recognize backend. This avoids asking the user for biometric data when authentication would fail anyway.

## Validate User and Device Active

### Android

```kotlin
Keyless.validateUserAndDeviceActive(
    onCompletion = { result ->
        when (result) {
            is Keyless.KeylessResult.Success -> Log.d("KeylessSDK ", "user and device active")
            is Keyless.KeylessResult.Failure -> Log.d("KeylessSDK ", "user or device not found - error code ${result.error.code}")
            // error code 1131 = user is not enrolled on the device (not even locally, so did not check on backend)
            // error code 534 = user not found or deactivated on backend
            // error code 535 = device not found or deactivated on backend
        }
    }
)
```

### iOS

```swift
Keyless.validateUserDeviceActive(
    completionHandler: { error in
        if let error = error {
            print("user or device deactivated")
            // error code 1131 = user is not enrolled on the device (not even locally, so did not check on backend)
            // error code 534 = user not found or deactivated on backend
            // error code 535 = device not found or deactivated on backend
        } else {
            print("user and device active")
        }
    }
)
```

### Flutter

```dart
try {
  await Keyless.validateUserAndDeviceActive();
  print("user and device active");
} catch (error) {
  print("user or device deactivated - error code: ${error.code}");
  // error code 1131 = user is not enrolled on the device (not even locally, so did not check on backend)
  // error code 534 = user not found or deactivated on backend
  // error code 535 = device not found or deactivated on backend
}
```

### React Native

```javascript
import Keyless from '@react-native-keyless/sdk';

const validateUserAndDevice = async () => {
  const result = await Keyless.validateUserAndDeviceActive();

  result.fold({
    onSuccess: () => {
      console.log("user and device active");
    },
    onFailure: (error) => {
      console.error(`user or device deactivated - error code: ${error.code}`);
      // error code 1131 = user is not enrolled on the device (not even locally)
      // error code 534 = user not found or deactivated on backend
      // error code 535 = device not found or deactivated on backend
    }
  });
};
```

## User Identifier

Retrieve the user identifier with `Keyless.getUserId()`.

### Android

```kotlin
fun getUserId(): KeylessResult<String, KeylessSdkError>
```

### iOS

```swift
func getUserId() -> Result<String, KeylessSDKError>
```

### Flutter

```dart
Future<String> getUserId() async
```

### React Native

```javascript
import Keyless from '@react-native-keyless/sdk';

const getUserId = async () => {
  const result = await Keyless.getUserId();

  result.fold({
    onSuccess: (userId) => {
      console.log("User ID:", userId);
    },
    onFailure: (error) => {
      console.error("Failed to get user ID:", error);
    },
  });
};
```

## Device Identifier

The device is identified by its public signing key. To retrieve it, use `Keyless.getDevicePublicSigningKey()`.

### Android

```kotlin
fun getDevicePublicSigningKey(): KeylessResult<ByteArray, KeylessSdkError>
```

### iOS

```swift
func getDevicePublicSigningKey() -> Result<String, KeylessSDKError>
```

### Flutter

```dart
Future<String> getDevicePublicSigningKey() async
```

### React Native

```javascript
import Keyless from '@react-native-keyless/sdk';

const getDevicePublicSigningKey = async () => {
  const result = await Keyless.getDevicePublicSigningKey();

  result.fold({
    onSuccess: (key) => {
      console.log("Device public key:", key);
    },
    onFailure: (error) => {
      console.error("Failed to get device public key:", error);
    },
  });
};
```

## PingOne Recognize SDK Reset

Resetting the PingOne Recognize SDK to a clean state deletes local data from the device, but does not de-enroll the user from the PingOne Recognize backend or deactivate the device from the PingOne Recognize backend.

### Android

```kotlin
fun reset(
  onCompletion: (KeylessResult<Unit, KeylessSdkError>) -> Unit
)
```

### iOS

```swift
func reset() -> KeylessSDKError?
```

### Flutter

```dart
Future<void> reset() async
```

### React Native

```javascript
import Keyless from '@react-native-keyless/sdk';

const resetSdk = async () => {
  const result = await Keyless.reset();

  result.fold({
    onSuccess: () => {
      console.log("SDK reset successfully");
    },
    onFailure: (error) => {
      console.error("SDK reset failed:", error);
    },
  });
};
```

## Lockout Management

The `getRateLimitInfo` API checks whether the user is currently rate-limited and, if so, for how many seconds. This API is typically used to provide feedback to users after multiple failed authentication attempts.

### Android

```kotlin
Keyless.getRateLimitInfo { result ->
    when (result) {
        is Keyless.KeylessResult.Success -> {
            val rateLimitInfo = result.value
            println("User is rate limited: ${rateLimitInfo.isRateLimited} with remaining seconds: ${rateLimitInfo.remainingSeconds}")
        }
        is Keyless.KeylessResult.Failure -> {
            println("Error: ${result.error.message}")
        }
    }
}
```

### iOS

```swift
Keyless.getRateLimitInfo(completion: { result in
    switch result {
    case .success(let success):
        print("User is rate limited: \(success.isRateLimited) with remaining seconds: \(success.remainingSeconds)")
    case .failure(let error):
        print("Error: \(error.message)")
    }
})
```

### Flutter

```dart
try {
    final rateLimitInfo = await Keyless.instance.getRateLimitInfo();
    print("User is rate limited: ${rateLimitInfo.isRateLimited} with remaining seconds: ${rateLimitInfo.remainingSeconds}");
} catch (error) {
    print("Error: $error");
}
```

### React Native

```javascript
import Keyless from '@react-native-keyless/sdk';

const getRateLimitInfo = async () => {
  const result = await Keyless.getRateLimitInfo();

  result.fold({
    onSuccess: (info) => {
      console.log(`User is rate limited: ${info.isRateLimited}, remaining seconds: ${info.remainingSeconds}`);
    },
    onFailure: (error) => {
      console.error("Error fetching rate limit info:", error);
    },
  });
};
```
