Mobile protocol
How the mobile app signs every step — and what that implies
A plain-language walk through the Ezkey mobile protocol: enrollment, proof tokens, and end-to-end cryptographic chaining.
01 — The world as it stands
In 2026, for most teams, strong authentication still means a password combined with a code sent by SMS or email. SMS traffic travels without end-to-end encryption across networks that offer no confidentiality guarantees. Email is no better as a channel for time-sensitive secrets. Yet these are the vectors that the majority of MFA systems in production rely on today.
Passkeys are arriving, and that is a good thing. Built on FIDO2, they offer a robust model grounded in platform security, steadily adopted by major players. But their rollout remains uneven — particularly for backend-first teams who operate far from client-side web frameworks.
The real problem may not be the shape of the code — six digits, a magic link, a push notification. The problem is the underlying trust model: who validates what, and how is that validation cryptographically anchored?
Ezkey proposes a third path. Not an alternative to passkeys: a more modest, pragmatic solution, stronger than OTP codes and SMS on the cryptographic security front, built for teams who want to understand and control what happens in their authentication chain.
02 — The anchor: trust comes from the backend
The Ezkey model rests on a principle already described in Ezkey at a glance: the self-hosted backend installation is the trust anchor. Not a third-party platform, not an opaque cloud service — the Ezkey instance deployed in the organization's own environment, under its direct control.
In this model, the mobile app is not a confirmation button. It is a full cryptographic participant. It holds a private key protected by the platform's built-in security mechanisms: on Android, that key is generated directly in the Android Keystore and — when the hardware supports it — in a dedicated hardware-backed cryptographic module (StrongBox). The key never leaves that boundary; it does not transit application memory, is not exportable, and is never stored in the clear.
This is the fundamental difference from a traditional push-to-approve model. In that model, the app receives a notification and the user taps "Yes." The trust channel is human. Here, the trust channel is cryptographic. The app signs.
03 — Enrollment: proving key possession
Enrollment proceeds in two phases — bind then verify — which form a cryptographically linked sequence.
Bind. The app presents an enrollmentProofToken — an opaque token provided out-of-band by the administration team when the account is created. This token is anti-enumeration: it is impossible to guess the existence of an enrollment by trying arbitrary values.
The backend responds by providing its integration public key and a signature over the response. The app verifies this signature before going any further. This is the first protection against a malicious intermediary: if an injected response is forged, signature verification fails and the flow stops there.
Verify. The app generates an EC P-256 key pair directly in the Android Keystore. It then builds a canonical signed payload:
enrollmentProofToken|enrollmentId|challengeResponse|devicePublicKey
It signs this string with its private key and sends the signature to the backend along with the corresponding public key. What is signed here is not just a challenge: it is the full context of the enrollment. The normalization is strict — separator |, UTF-8 encoding, no ambiguity about what the signature covers.
This level of precision is not rigor for its own sake: it is what makes the proof verifiable and non-reinterpretable. The backend verifies and counter-signs in turn. The app validates that final signature before treating enrollment as complete. At this point, both parties have proven their cryptographic identity in both directions.
Schematically, the enrollment flow looks like this:
bind · enrollmentProofToken (out-of-band)
Backend
verify · public key + full context signed ECDSA · enrollmentProofToken|enrollmentId|challenge|devicePublicKey
Backend
04 — The Proof Token: non-replayable material
Ezkey uses three types of tokens in its protocol, each with a distinct role.
enrollmentProofToken— provided out-of-band at enrollment, stable for the entire duration of the enrollment flow. It identifies the enrollment context opaquely, without exposing any guessable surface.deviceProofToken— generated by the app on each poll, from the platform's cryptographically secure random number generator. It is signed with the enrollment key. Its role: prove the freshness of the call. Replaying a previousdeviceProofTokendoes not work.authAttemptProofToken— issued by the backend for each authentication attempt, single-use. This is the central material of the cryptographic chain betweenpendingandrespond.
The simplest analogy: think of a notarized declaration. Each act carries a precise date, a specific context, and a unique signature. You cannot photocopy the act and use it in a different context. Proof tokens work on exactly that principle.
05 — Authentication: a fully signed round trip
Authentication proceeds in two steps: pending then respond.
Pending. The app signals its presence with a signed deviceProofToken — proof that this call is fresh. If the backend has a pending authentication attempt for this device, it responds with an authAttemptProofToken, signed by the integration key established at enrollment.
The app verifies this signature before displaying anything to the user. This is the decisive point. If a malicious proxy intercepts the communication and injects a forged response, it cannot sign it with the integration key: that key is known only to the legitimate backend, and it was anchored in the app at enrollment. Verification fails, the app rejects the response, the user sees nothing.
The chain link. The authAttemptProofToken received in pending is precisely the material signed in respond. The app signs:
authAttemptProofToken|true
— or false if the user declines. This is not an implementation detail: it is the cryptographic link between the two steps. A valid respond cannot be constructed without having genuinely received this token in the pending response. The two calls are cryptographically linked, not merely time-sequential.
Respond. The backend verifies the app's signature. It signs the result in turn. The app verifies that signature before displaying the final outcome.
Schematically, the full authentication flow looks like this:
pending · signed deviceProofToken
Backend
authAttemptProofToken signed Ed25519
✓ verified by the app before display
Backend
respond · signed authAttemptProofToken|decision
Backend
Four verification points. No step ends on implicit trust.
06 — What it protects against — and the honest limits
Replay. The authAttemptProofToken is tied to a specific attempt and is single-use. Replaying a previous respond request produces nothing: the token is consumed.
Interception (MITM). A malicious proxy cannot forge a credible pending response. The integration key is established at enrollment — it does not travel in the authentication flow. No response unsigned by that key passes the app's verification.
Enumeration. Enrollment tokens are opaque. There is no guessable surface that would allow probing the existence of an enrollment by trial and error.
Limits — documented in full transparency.
The devicePrivateKeyStorageTier field is a client assertion. The app declares whether its private key benefits from hardware-backed protection. The backend records that declaration; it cannot verify it cryptographically. A malicious client could declare a protection level it does not have. This is a known, explicitly documented limitation — not a hidden flaw.
More fundamentally: Ezkey does not provide an end-to-end PKI/CA certificate chain. The self-hosted backend is the trust anchor by design. There is no independent certificate authority that validates the identity of the Ezkey server to the device via an externally verifiable chain of certificates. Trust in the backend rests on the fact that it is your backend — installed, operated, and controlled by your organization. This is a deliberate design choice, consistent with the self-hosting model, and a known limitation that is a candidate for future protocol evolution.
07 — The third path: honesty about what Ezkey is (and is not)
There are three broad approaches to strong authentication today:
Ezkey is Android-first today, with iOS planned in a future release. It is an open-source project, in active development. Being opinionated is not a weakness when the security assumptions are made explicit, documented, and verifiable. That is precisely what the protocol strives to guarantee at every step.
08 — Going further
The strength of the Ezkey protocol rests not on a promise — it rests on verifiable signatures at every step. Each one can be audited independently, using standard platform cryptographic libraries, with no dependency on Ezkey tooling.
- Test locally: the Docker stack starts cleanly with
./ezkey-tests/clean-start.sh; the Crypto API (localhost:9090) generates real key pairs and signatures to validate an implementation in minutes - Related article: Ezkey at a glance — trust zone, mobile, and core flows
Français : Version française de cet article