PingOne Recognize

Secret management

The Secret Management feature allows you to securely store, retrieve, update, and delete secrets during enrollment or authentication flows. Secrets can be anything you can save as an ASCII string (such as an API key provided via backend or the seed of an OTP protocol) and are stored in the PingOne Recognize Secrets Vault, associated with the user’s PingOne Recognize ID.

Secret Management operations are performed as part of the biometric flow, ensuring user authentication before any secret modification.

Key class

The KeylessSecret class represents a secret stored in the Keyless Secrets Vault:

  • Android

  • iOS

public class KeylessSecret(
    public val id: Identifier,  // Unique identifier for the secret
    public val value: Value     // The actual secret content
)
public struct KeylessSecret {
public let id: Identifier   // Unique identifier for the secret
public let value: Value     // The actual secret content
}

Configuration parameters

Secret Management parameters are available in both BiomEnrollConfig and BiomAuthConfig and the same APIs work for both enrollment and authentication flows. You can adapt any sample shown below by replacing Keyless.enroll with Keyless.authenticate and using the corresponding configuration class.

Parameter

Type

Description

savingSecret

KeylessSecret?

Secret to create or update

deletingSecret

KeylessSecret.Identifier?

SecretID to delete

retrievingSecret

KeylessSecret.Identifier?

Secret ID to retrieve

shouldRetrieveSecretIDs

Boolean

Whether to retrieve all secret IDs. The default is false.

Operations

Create or update a secret

  • Android

  • iOS

val configuration = BiomEnrollConfig(
    savingSecret = KeylessSecret.of(
        id = "your-secret-id",
        value = "your-secret-value"
    )
)

Keyless.enroll(configuration = configuration) { keylessResult ->
    // Handle the result
}
let configuration = BiomEnrollConfig(
    savingSecret: KeylessSecret(
        id: "your-secret-id",
        value: "your-secret-value"
    )
)

Keyless.enroll(
    configuration: configuration,
    onCompletion: { result in
        switch result {
        case .success(let success):
            print("Secret saved successfully")
        case .failure(let error):
            print("Error: \(error.message)")
        }
    })

Retrieve a secret

  • Android

  • iOS

val configuration = BiomAuthConfig(
    retrievingSecret = KeylessSecret.Identifier("your-secret-id")
)

Keyless.authenticate(configuration = configuration) { keylessResult ->
    if (keylessResult is KeylessResult.Success) {
        val secret = keylessResult.value.secret
    }
}
let configuration = BiomAuthConfig(
    retrievingSecret: "your-secret-id"
)

Keyless.authenticate(
    configuration: configuration,
    onCompletion: { result in
        switch result {
        case .success(let success):
            if let secret = success.secret {
                print("Secret ID: \(secret.id)")
                print("Secret Value: \(secret.value)")
            }
        case .failure(let error):
            print("Error: \(error.message)")
        }
    })

Delete a secret

  • Android

  • iOS

val configuration = BiomAuthConfig(
    deletingSecret = KeylessSecret.Identifier("your-secret-id")
)

Keyless.authenticate(configuration = configuration) { keylessResult ->
    // Handle the result
}
let configuration = BiomAuthConfig(
    deletingSecret: "your-secret-id"
)

Keyless.authenticate(
    configuration: configuration,
    onCompletion: { result in
        switch result {
        case .success:
            print("Secret deleted successfully")
        case .failure(let error):
            print("Error: \(error.message)")
        }
    })

List all secret IDs

  • Android

  • iOS

val configuration = BiomAuthConfig(shouldRetrieveSecretIDs = true)

Keyless.authenticate(configuration = configuration) { keylessResult ->
    if (keylessResult is KeylessResult.Success) {
        val secretIDs = keylessResult.value.secretIDs
    }
}
let configuration = BiomAuthConfig(shouldRetrieveSecretIDs: true)

Keyless.authenticate(
    configuration: configuration,
    onCompletion: { result in
        switch result {
        case .success(let success):
            if let secretIDs = success.secretIDs {
                for id in secretIDs {
                    print("Secret ID: \(id)")
                }
            }
        case .failure(let error):
            print("Error: \(error.message)")
        }
    })

Combining operations

Multiple secret operations can be combined in a single flow:

  • Android

  • iOS

val configuration = BiomAuthConfig(
    savingSecret = KeylessSecret.of(
        id = "new-secret-id",
        value = "new-secret-value"
    ),
    retrievingSecret = KeylessSecret.Identifier("existing-secret-id"),
    shouldRetrieveSecretIDs = true
)

Keyless.authenticate(configuration = configuration) { keylessResult ->
    if (keylessResult is KeylessResult.Success) {
        val retrievedSecret = keylessResult.value.secret
        val allSecretIDs = keylessResult.value.secretIDs
    }
}
let configuration = BiomAuthConfig(
    savingSecret: KeylessSecret(
        id: "new-secret-id",
        value: "new-secret-value"
    ),
    retrievingSecret: "existing-secret-id",
    shouldRetrieveSecretIDs: true
)

Keyless.authenticate(
    configuration: configuration,
    onCompletion: { result in
        switch result {
        case .success(let success):
            if let secret = success.secret {
                print("Retrieved secret: \(secret.value)")
            }
            if let secretIDs = success.secretIDs {
                print("All secret IDs: \(secretIDs)")
            }
        case .failure(let error):
            print("Error: \(error.message)")
        }
    })

Resulting objects

When secret operations are included in a flow, the retrieved secrets and secret IDs are available in the respective result objects. Please refer to Enrollment success result and Authentication success result for more details.

Error Handling

When retrieving or deleting a secret that does not exist, the SDK returns a 20003 - Secret Not Found error and halts the operation.