Mobile App
The IDToken mobile app is the user’s authenticator and credential wallet. Built with Flutter for iOS and Android, it serves three roles:
| Role | Description |
|---|---|
| Credential store | Holds the IDToken VDS (QR image + decoded payload including photo) |
| OTP verifier | Displays the server-generated OTP for visual comparison with the browser |
| Cryptographic prover | Signs authentication approvals with a device-bound ECDSA P-256 private key |
User Screens
Section titled “User Screens”Enrollment Flow
Section titled “Enrollment Flow”- User taps “Enroll my IDToken”
- Camera opens — scan the IDToken QR code
- App parses and verifies the VDS locally (ECDSA signature check, expiry check)
- id3 Face SDK performs liveness detection (passive + active anti-spoofing) and 1:1 match against the VDS face template
- App generates an ECDSA P-256 key pair in the device’s secure element (iOS Secure Enclave / Android Keystore StrongBox)
- App calls
POST /enrollwith the VDS data, public key, device ID, and FCM token - IDToken stored locally in encrypted storage — the user sees the “Home” screen
Authentication Flow
Section titled “Authentication Flow”- FCM data push received (OTP is never shown as a system notification — only data messages)
- App opens the consent screen showing:
- Service name and logo
- Requested scopes with toggleable switches
- “This service will NOT receive” list (updates dynamically)
- OTP for visual comparison
- Countdown timer
- User compares OTP, toggles scopes, taps Approve & Share
- id3 Face SDK verifies the user (liveness + 1:1 match against VDS face template)
- App constructs the signed message:
sessionId|otp|timestamp|grantedScopes - ECDSA signature computed in the secure element
- App calls
POST /auth/verifywith the signature and granted scopes - “Approved” checkmark shown — return to Home
Secure Key Management
Section titled “Secure Key Management”The ECDSA P-256 key pair is hardware-bound and non-exportable:
| Platform | Secure Element | Key Properties |
|---|---|---|
| iOS | Secure Enclave | Keys are generated and used entirely within the enclave; never leave the hardware |
| Android | Android Keystore (StrongBox if available) | Hardware-backed; signing operations happen inside the TEE/SE |
The public key is exported (PEM format) and sent to the auth server during enrollment. The private key is only used for signing — the app requests a signature from the secure element, passing the message to be signed.
Error Handling
Section titled “Error Handling”| Scenario | Behavior |
|---|---|
| OTP expires before approval | ”Session expired” screen; user re-initiates on browser |
| Phone lost | Present physical document, re-enroll (old tokenId revoked) |
| Face no longer matches | Re-enroll with document (new VDS with updated photo) |
| App deleted | Re-install, re-enroll (new keypair generated) |
| Multiple devices | Each device has its own keypair; same tokenId can have multiple enrollments |
| No network during signing | Offline signing works; POST /verify retried on reconnect |
Data Storage
Section titled “Data Storage”The IDToken credential is stored in platform-specific encrypted storage (iOS Keychain / Android EncryptedSharedPreferences). The stored data includes:
| Field | Description |
|---|---|
tokenId | Unique VDS identifier |
givenName, familyName | Name from the credential |
dateOfBirth, nationality | Identity attributes |
expiresAt | Credential expiry date |
photoBase64 | Portrait photo (WEBP) |
faceTemplateBase64 | Biometric face template for 1:1 matching |
qrImageBase64 | Original QR code image |
enrolledAt | Enrollment timestamp |
The credential is never uploaded to any server after enrollment — the server only stores the public key and tokenId.