How to configure authentication requirements for credentials using Device Key Authentication
Overview
This guide demonstrates how to use Device Key Authentication to control what user authentication methods (such as face authentication, fingerprint authentication, or the device passcode) are required when claiming and presenting credentials in your wallet applications.
When the SDK is initialized, the UserAuthConfiguration structure defines the default authentication behavior for the wallet application, including settings like when authentication is required and the timeout duration.
Device Key Authentication gives you fine-grained control over the security posture of specific credentials. By specifying a per-credential authentication policy, you can require stronger methods for sensitive credentials while allowing more convenient access for less sensitive ones.
When you specify a DeviceKeyAuthenticationPolicy during credential claiming or presentation, it overrides the general UserAuthConfiguration settings for that specific operation. This means that the authentication requirements defined in the DeviceKeyAuthenticationPolicy take precedence over the broader wallet-level settings. Conversely, if no DeviceKeyAuthenticationPolicy is specified, the SDK falls back to the UserAuthConfiguration settings for authentication behavior.
Each policy leverages whatever user authentication modalities are currently configured at the operating system level (e.g., enrolled face authentication / fingerprints and an active device passcode). The wallet does not manage biometric enrollment. It relies on the device’s Secure Enclave / Keystore settings. By choosing the appropriate policy, you align credential protection directly with the user’s device-level security configuration.
Prerequisites
This guide builds on the Credential Claiming tutorial. It is recommended to complete that tutorial first, then return here to learn how to configure device key authentication policies.
Understanding Device Key Authentication
What is Device Key Authentication?
Device Key Authentication is a feature that allows you to specify which type of user authentication is required to access the cryptographic keys protecting each credential. These keys are generated on the user's device and are used for:
- Secure credential claiming: Authenticate the user when a new credential is being claimed and stored in the wallet.
- Secure credential usage: Authenticate the user when an existing credential is accessed, either to view it in the wallet or to present it to a verifier (in-person or remotely).
By configuring a device key authentication policy, you can define the level of security required for each credential based on its sensitivity and use case.
Device Key Authentication enables you to:
- Match security to sensitivity: Require stronger authentication (like biometrics) for high-value credentials such as government IDs, while allowing passcode-only access for lower-risk credentials like membership cards.
- Improve user experience: Balance security with convenience by allowing users to choose appropriate authentication methods for different credential types.
- Maintain consistency: Ensure the same authentication method used during credential claiming is required during presentation, providing a predictable and secure user experience.
- Meet compliance requirements: Satisfy regulatory or organizational requirements that mandate specific authentication methods for certain credential types.
How it works
When you configure a device key authentication policy for a credential:
- During claiming: The user must authenticate using the specified method before the credential can be stored in their wallet.
- During access: The same authentication method is required before the credential can be accessed, either to view it in the wallet or to present it to a verifier (in-person or remotely).
The authentication policy is bound to the device key that protects the credential, ensuring consistent security throughout the credential's lifecycle.
Available authentication options
The Holder SDKs provide several authentication policy options:
The iOS Holder SDK authentication policy options map directly to Apple's SecAccessControlCreateFlags:
| UserAuthenticationType | Biometry | Credential valid after biometry changed | Lockscreen | Security level |
|---|---|---|---|---|
biometryCurrentSet | ✅ | ❌ | ❌ | Highest |
biometryAny | ✅ | ✅ | ❌ | High |
deviceCredential | ❌ | ✅ | ✅ | Medium |
userPresence | ✅ | ✅ | ✅ | Lowest |
biometryAny: Adding or removing biometric data does not invalidate keys (e.g., user adds a new TouchID enrollment or deletes an existing FaceID enrollment after claiming the credential. Existing device keys remain usable and no re-provisioning is required). Maps to Apple'sSecAccessControlCreateFlags.biometryAny.biometryCurrentSet: Adding or removing biometric data invalidates the key (e.g., user adds a new TouchID enrollment or deletes an existing FaceID enrollment after claiming the credential. The underlying device key becomes unusable and the credential is invalid. The user must re-claim the credential from the issuer). Maps to Apple'sSecAccessControlCreateFlags.biometryCurrentSet.deviceCredential: Key remains valid if passcode changes but becomes invalid if passcode is removed. Maps to Apple'sSecAccessControlCreateFlags.devicePasscode.userPresence: Requires user presence (biometry or passcode) each access. Adding/removing biometry does not invalidate keys. Maps to Apple'sSecAccessControlCreateFlags.userPresence.
If a credential’s authentication policy differs from the policy set at SDK initialization, the user may see two authentication prompts. One prompt enforces the SDK-level policy; the other enforces the credential’s policy (each tied to a different key). This can occur when:
- The user attempts to retrieve or access a credential shortly after initialization.
- At least five minutes have passed since initialization and the user then attempts to retrieve or access a credential.
| UserAuthenticationType | Biometry | Credential valid after biometry changed | Lockscreen | Security level |
|---|---|---|---|---|
BiometryCurrentSet | ✅ | ❌ | ❌ | Highest |
BiometryAny | ✅ | ✅ | ❌ | High |
DeviceCredential | ❌ | ✅ | ✅ | Medium |
UserPresence | ✅ | ✅ | ✅ | Lowest |
BiometryAny: Adding or removing biometric data does not invalidate keys (e.g., user adds a new fingerprint or deletes an existing face authentication enrollment after claiming the credential. Existing device keys remain usable and no re-provisioning is required).BiometryCurrentSet: Adding or removing biometric data invalidates the key (e.g., user adds a new fingerprint or deletes an existing face authentication enrollment after claiming the credential. The underlying device key becomes unusable and the credential is invalid. The user must re-claim the credential from the issuer).DeviceCredential: Key remains valid if passcode changes but becomes invalid if passcode is removed.UserPresence: Requires user presence (biometry or passcode) each access. Adding/removing biometry does not invalidate keys.
Coming soon...
Configuring Device Key Authentication
To configure device key authentication, you need to specify a DeviceKeyAuthenticationPolicy when calling the retrieveCredentials method during the credential claiming flow.
Step 1: Create a DeviceKeyAuthenticationPolicy
First, create a DeviceKeyAuthenticationPolicy object that defines the authentication requirements:
let deviceKeyAuthPolicy = DeviceKeyAuthenticationPolicy(
type: .biometryAny
)The DeviceKeyAuthenticationPolicy takes a single parameter:
type: The type of user authentication required. Choose from one of the options detailed above.
First, create a DeviceKeyAuthenticationPolicy object that defines the authentication requirements:
val deviceKeyAuthPolicy = DeviceKeyAuthenticationPolicy(
type = UserAuthenticationType.BiometryAny
)The DeviceKeyAuthenticationPolicy takes a single parameter:
userAuthenticationType: The type of user authentication required. Choose from one of the options detailed above.
Coming soon...
Step 2: Pass the policy to retrieveCredentials
Update your retrieveCredential function from the Credential Claiming tutorial to include the deviceKeyAuthenticationPolicy parameter:
func retrieveCredential(transactionCode: String?) {
Task {
do {
// Create the device key authentication policy
let deviceKeyAuthPolicy = DeviceKeyAuthenticationPolicy(
type: .biometryAny
)
let retrievedCredentialResults = try await mobileCredentialHolder.retrieveCredentials(
credentialOffer: discoveredCredentialOfferURL,
clientId: Constants.clientId,
transactionCode: transactionCode,
deviceKeyAuthenticationPolicy: deviceKeyAuthPolicy
)
Task {
var credentials: [MobileCredential] = []
for result in retrievedCredentialResults {
if let credentialId = result.credentialId {
if let credential = try? await mobileCredentialHolder.getCredential(credentialId: credentialId) {
credentials.append(credential)
}
}
}
self.retrievedCredentials = credentials
navigationPath = NavigationPath()
navigationPath.append(NavigationState.retrievedCredentials)
}
} catch {
print(error.localizedDescription)
}
}
}Update your onRetrieveCredentials function from the Credential Claiming tutorial to include the DeviceKeyAuthenticationPolicy parameter:
private fun onRetrieveCredentials(
coroutineScope: CoroutineScope,
activity: Activity,
navController: NavController,
transactionCode: String
) {
coroutineScope.launch {
try {
val deviceKeyAuthPolicy = DeviceKeyPolicy(
DeviceKeyAuthenticationPolicy(type = UserAuthenticationType.BiometryAny)
)
val mdocHolder = MobileCredentialHolder.getInstance()
val retrieveCredentialResults = mdocHolder.retrieveCredentials(
activity,
SharedData.scannedOffer!!,
clientId = "android-mobile-credential-tutorial-holder-app",
transactionCode = transactionCode,
deviceKeyAuthPolicy
)
SharedData.retrievedCredentials = retrieveCredentialResults.mapNotNull {
try {
mdocHolder.getCredential(it.credentialId!!, skipStatusCheck = true)
} catch (e: Exception) {
val msg = "Failed to get credential from storage"
Toast.makeText(activity, msg, Toast.LENGTH_SHORT).show()
null
}
}
navController.navigate("retrievedCredential")
SharedData.discoveredCredentialOffer = null
} catch (e: Exception) {
Toast.makeText(activity, "Failed to retrieve credentials", Toast.LENGTH_SHORT).show()
}
}
}Coming soon...
Understanding the complete flow
When you call retrieveCredentials with a deviceKeyAuthenticationPolicy:
- The SDK generates a device key with the specified authentication requirements.
- The user is prompted to authenticate using the specified method (e.g., Face ID or fingerprint).
- The authentication requirement is bound to the access control of the generated device key, and that key is cryptographically bound to the credential.
- Once authenticated, the credential is claimed and securely stored.
- Future access to this credential (during presentation workflows) will require the same authentication method.
Verifying the authentication policy
You can inspect the authentication policy associated with a credential by accessing its metadata:
if let credential = try? await mobileCredentialHolder.getCredential(credentialId: credentialId) {
if let authInfo = credential.metadata.deviceKeyAuthenticationInfo {
print("User authentication type: \(authInfo.type?.rawValue ?? "not set")")
}
}The deviceKeyAuthenticationInfo property returns a DeviceKeyAuthenticationInfo object containing:
type: The authentication type configured for this credential's device key.
val credentialMetadata = mobileCredentialHolder.getCredentials().first { it.id == credentialId }
credentialMetadata.deviceKeyPolicy?.authentication?.type?.let {
println("User authentication type: $it")
}The deviceKeyPolicy property returns a DeviceKeyPolicyInfo object with authentication property, containing:
type: The authentication type configured for this credential's device key.timeoutSeconds: Timeout for user authentication.
Coming soon...
Testing Device Key Authentication
To test the device key authentication feature:
- Complete the credential claiming flow with a configured
deviceKeyAuthenticationPolicyas described above. - Observe the authentication prompt during claiming (e.g., Face ID, Touch ID, or passcode prompt).
- Attempt to present the credential using either:
- Verify the same authentication method is required during presentation.
Testing with different authentication policies requires re-claiming credentials, as the policy is bound to the device key generated during the claiming process.
How would you rate this page?