# 5️⃣ User and device management

The Keyless SDK "caches" the enrolled user locally on the device.

There are some use cases where it is possible to [delete the user from server API](https://docs.keyless.io/consumer/server-api/users) and [delete the device from server API](https://docs.keyless.io/consumer/server-api/devices). The Keyless SDK will not be notified about such deletions. For this reason if you try to authenticate a user or a device that have been deleted from server API you will get an error.

Call `validateUserAndDeviceActive` **before** authenticating, to validate that both the user and the device are still active in the Keyless backend, to avoid asking the user for biometric data which will still not let them authenticate.

{% tabs %}
{% tab title="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 ofund - 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
        }
    }
)
```

{% endtab %}

{% tab title="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")
        }
    }
)
```

{% endtab %}

{% tab title="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
}
```

{% endtab %}

{% tab title="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
    }
  });
};
```

{% endtab %}
{% endtabs %}

## User identifier

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

{% tabs %}
{% tab title="Android" %}

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

{% endtab %}

{% tab title="iOS" %}

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

{% endtab %}

{% tab title="Flutter" %}

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

{% endtab %}

{% tab title="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);
    },
  });
};
```

{% endtab %}
{% endtabs %}

## Device identifier

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

{% tabs %}
{% tab title="Android" %}

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

{% endtab %}

{% tab title="iOS" %}

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

{% endtab %}

{% tab title="Flutter" %}

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

{% endtab %}

{% tab title="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);
    },
  });
};
```

{% endtab %}
{% endtabs %}

## Keyless SDK reset

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

{% tabs %}
{% tab title="Android" %}

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

{% endtab %}

{% tab title="iOS" %}

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

{% endtab %}

{% tab title="Flutter" %}

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

{% endtab %}

{% tab title="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);
    },
  });
};
```

{% endtab %}
{% endtabs %}

## 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.

{% tabs %}
{% tab title="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}")
        }
    }
}
```

{% endtab %}

{% tab title="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)")
    }
})
```

{% endtab %}

{% tab title="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");
}
```

{% endtab %}

{% tab title="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);
    },
  });
};
```

{% endtab %}
{% endtabs %}
