Factors & levels
ReadyA signed response carries one of two levels: the user unlocked the device, or the user passed a biometric check with no passcode fallback. Location, number matching and codes are separate dimensions, chosen independently — not stronger levels. You request what an action needs per call; the server enforces it, and a device that cannot meet it is denied rather than silently downgraded.
Who this is for: anyone deciding how much proof a given action needs. Match the friction to the stakes — a glance for a login, a signed-and-located approval for a wire transfer. To set the level on a call, see IssueAuthChallenge.
Two signed levels#
The signature a device returns states which check the person passed. There are two such states, the level travels inside the signed payload, and it comes back to you on the result. Because it is signed, nothing between the phone and the deployment can change it, and the deployment refuses any approval below the level you asked for. A refusal is exempt, so the level recorded against a decline can be lower than the one you demanded.
Device unlock DEVICE_ACCESS
The user unlocked the phone — by face, by fingerprint, or by the device passcode. Proves that somebody with access to the phone is present.
deviceOwnerAuthentication · Android BIOMETRIC_STRONG | DEVICE_CREDENTIALBiometric only BIOMETRIC
A face or fingerprint check with no fall back to a passcode. The distinction carries more weight than it first appears: a passcode is something a person can be made to disclose, or can be observed being typed. Removing the fallback narrows who can produce a signature to the person the phone was set up with.
Three separate dimensions#
These are not stronger versions of the two levels above, and they are chosen independently of them.
- Location — was the phone where it had to be.
- Number matching — was the user reading the screen where the action started.
- Codes — a time-based one-time code (RFC 6238), the baseline for a user with no enrolled phone at all. A code proves possession of a shared secret; it does not bind a specific action.
A ladder implies each step contains the one below it, and that is false here. A location check tells you nothing about who was holding the phone, and a biometric check tells you nothing about where they were. Presented as one scale, asking for “level 3” would look like it granted everything beneath it — so they are requested separately, and each is answered separately.
You choose per action#
The level is not a global setting — you request a minimum strength on each challenge, so the same user glides through a login and is asked for more only when the stakes rise. Signing in might ask for level 1; changing an email address, level 2; paying a supplier, level 2 with number matching and a location check. That decision belongs in your own backend, which is the only place that knows what an action is worth. You must set a level explicitly — MIN_STRENGTH_REQUIRED rejects a call that leaves it unset, because a silent default would defeat the point.
The server owns the policy#
Strength is checked by the server in two places, so a device cannot have a weaker check accepted where you demanded a stronger one:
- At issuance — if the capabilities the user’s phones last reported cannot meet the requested level (e.g. a biometric-only check asked of a phone with no biometric enrolled), the call is rejected up front with
DEVICE_INCAPABLE. A report older than 24 hours does not count. Downgrade the requirement or prompt the user to enroll a stronger device. - At verification — the device stamps the actual strength it achieved into the signed payload. If an approval is below what the challenge demanded, the server rejects it with
AUTH_STRENGTH_INSUFFICIENT— the cryptographic backstop behind the on-device checks. A decline is not held to that bar, so the level recorded against one can be lower.
A device that cannot meet the required level fails the challenge — it is never quietly dropped to a weaker factor. Degradation is always visible to you and to the user; an approval is at the strength you asked for or above it, and anything else is refused rather than quietly weakened. A refusal below your floor is still recorded as a refusal, and an approval below it never becomes a result at all — the submit is refused and the challenge stays live, so the device can answer again at a higher level. See Errors for the full set.
Device capability & attestation#
Every response carries the strength the device reports it performed, signed into the payload with the phone’s own key, and it reaches your server as auth_strength on the challenge result — so a secure-element biometric is not recorded as the same thing as a 2D-camera face unlock. The level is the phone’s statement about itself. This matters: not all “face unlock” is equal. On iOS, Face ID is backed by the Secure Enclave; on Android, only a hardware-backed Class-3 biometric qualifies, and many devices’ face unlock is a 2D-camera convenience feature that Ydentifi will not count as a strong factor.
Attestation answers a different question: is this the genuine app? At launch, the Ydentifi iOS app uses Apple’s App Attest, so a deployment can check that a request comes from the genuine Ydentifi app on a genuine Apple device. It does not prove which check the person passed. That is still the signed level above.
Location, precisely#
A location check evaluates the geofence on the device and returns only a coarse bucket — within radius, near, or far — never raw coordinates. Enforcement is your choice: advisory (recorded but not blocking) or required (a mismatch denies the challenge with LOCATION_MISMATCH). Because the position comes from the device’s GPS rather than a network IP, it is not defeated by a proxy or VPN. The result is what the phone reports; Ydentifi does not verify the phone’s location hardware.