@@ -44,7 +44,8 @@ Since this is a strategy, it supports all the same hooks as the other strategies
4444- With ` first_factor ` enabled, a key protected by an app PIN or platform biometrics is a complete passwordless login granting AAL2
4545 — see [ How it works] ( #how-it-works ) and [ Configuration] ( #configuration ) .
4646- Using the admin API, it is possible to delete all keys for a device on behalf of the user in case of theft or loss.
47- - A device may have multiple keys, to support multiple user accounts on the same device.
47+ - A device may have multiple keys, to support multiple user accounts on the same device. An identity can enroll at most 30 device
48+ keys.
4849- Only these platforms are currently supported, because they offer native APIs, strong hardware, and trust guarantees:
4950 - iOS: 14.0+
5051 - iPadOS: 14.0+
@@ -193,8 +194,9 @@ hardware-binding guarantees that this strategy relies on.
193194# # Protocol reference
194195
195196All flows are native (API) flows. The flow's UI contains a hidden `deviceauthn_nonce` node; its value is the base64 encoding of
196- the JSON `{"nonce":"<base64 of 32 raw bytes>"}`. Decode twice to obtain the raw nonce bytes. The nonce is single-use and bound to
197- the flow.
197+ the JSON `{"nonce":"<base64>"}`. Decode twice to obtain the raw nonce bytes. The nonce is single-use and bound to the flow. Treat
198+ it as opaque bytes : do not hard-code its length, which may change in the future — decode whatever the flow provides and feed it to
199+ the operations below as-is.
198200
199201# ## Enrollment
200202
@@ -255,7 +257,7 @@ Runs in a settings flow under a privileged session.
255257 challenge = SHA256(nonce ‖ t_pub)
256258 ` ` `
257259
258- The raw 32-byte nonce concatenated with the raw 32-byte transport public key, in that order, hashed once. This binds the
260+ The raw nonce bytes concatenated with the raw 32-byte transport public key, in that order, hashed once. This binds the
259261 transport key to the attested device : an intermediary that swaps `t_pub` invalidates the attestation.
260262
261263 :::warning
@@ -443,10 +445,9 @@ possession of the enrolled key:
443445}
444446` ` `
445447
446- - ` signature` covers the challenge `nonce ‖ t_pub` — the raw 64-byte concatenation of the settings-flow nonce and the fresh
447- transport public key, **not hashed by the caller**. Android signs it with `SHA256withECDSA` as usual; iOS passes it as
448- ` clientDataHash` to `generateAssertion`. This binding ensures a session-level attacker cannot rotate the secret to a transport
449- key they control.
448+ - ` signature` covers the challenge `nonce ‖ t_pub` — the raw concatenation of the settings-flow nonce and the fresh transport
449+ public key, **not hashed by the caller**. Android signs it with `SHA256withECDSA` as usual; iOS passes it as `clientDataHash` to
450+ ` generateAssertion` . This binding ensures a session-level attacker cannot rotate the secret to a transport key they control.
450451- Only PIN keys can be rotated.
451452- Effects : fresh secret (delivered via the same one-time `continue_with`), failure counter reset, `locked` state cleared.
452453
@@ -548,7 +549,7 @@ rotated, and delaying sensitive operations after either event.
548549 nonce. PIN enrollment binds the transport key : use `SHA256(nonce ‖ transport_public_key)` as the challenge. The bare nonce is
549550 correct only for second-factor device binding and biometric enrollment.
550551- **`The rotation signature is invalid.`** — the rotation signature must cover the raw concatenation
551- ` nonce ‖ transport_public_key` (64 bytes, not hashed by the caller, transport key generated fresh for this rotation).
552+ ` nonce ‖ transport_public_key` (not hashed by the caller, transport key generated fresh for this rotation).
552553- **Login always fails with the same generic error** — by design the server returns one identical error for an unknown key, a bad
553554 signature, a wrong PIN, and a locked key. Track wrong-PIN retries locally; after `pin_max_attempts` consecutive failures assume
554555 the key is locked and offer recovery.
0 commit comments