Better
Authenticator
App-switch fatigue, and a worse problem
Every 2FA login pulls you out of context. Open the authenticator app, scroll to the right account, memorise six digits in thirty seconds, switch back, type, hit submit before the code expires. Now do that fifteen times a day. The cost is not security, the cost is friction.
The deeper problem is the clipboard. Most authenticator apps recommend long-press + copy as the "fast" path. The clipboard is shared with every app on the device, persists across launches, and is read freely by third-party keyboards and pasteboard-watching apps. A 2FA code in the clipboard is a 2FA code anyone can read.
2FA codes on your keyboard
Better Authenticator is a custom iOS keyboard. When you switch to it inside any app, your TOTP codes appear in a horizontal scroll above the QWERTY layout, each with a live countdown ring. One tap and the code is injected directly into the active text field through Apple's textDocumentProxy.insertText(). No clipboard, no copy, no paste, no app switch.
Three components
App Group, not network
The keyboard extension cannot read the companion app's files. It cannot make network requests without "Allow Full Access". So how does it know your TOTP secrets? Through a shared Keychain access group, scoped by an App Group identifier.
The companion app writes secrets to the shared Keychain under kSecAttrAccessibleAfterFirstUnlock. The keyboard extension, signed with the same App Group entitlement, reads them back. Generating a TOTP code is pure local math (HMAC-SHA1 over the secret and the time counter), so the keyboard never touches the network. iOS' 50 MB memory limit for keyboard extensions is plenty.
Stack
Choices that matter
- Refuse "Allow Full Access". Most third-party keyboards demand it. We do not. The whole architecture is designed so that the keyboard never needs network, GPS, camera, or anything that would justify the prompt. Users get the keyboard with the smallest possible attack surface.
- Bypass the clipboard.
textDocumentProxy.insertText()writes straight into the text field. The code never touches the pasteboard, never persists, and never leaks to other apps. - Biometric on the companion, not the keyboard. The keyboard cannot present a FaceID prompt mid-typing without breaking the flow. So the companion app is biometric-gated for setup, and the codes themselves are guarded by being usable only when iOS itself is unlocked (
kSecAttrAccessibleAfterFirstUnlock). - iCloud Keychain sync is opt-in. Default is local-only. Users who want their codes on a second device flip a toggle, which sets
kSecAttrSynchronizableon each secret. The default makes the strongest privacy choice for them.
Threat model
TOTP secrets live in the iOS Keychain with shared access group com.keyauth.shared, scoped to the App Group, accessible only after first device unlock. The keyboard extension has zero network entitlement. The companion app uses biometric unlock and auto-locks on background. Codes are inserted via insertText, so they never enter the pasteboard. iCloud Keychain sync, when enabled, inherits Apple's end-to-end encryption.
What ships today
Better Authenticator is live as an iOS keyboard. RFC 6238 compliant TOTP with SHA1, SHA-256, and SHA-512, 6-, 7-, and 8-digit codes, and 30-second or 60-second periods. Standard otpauth:// URI imports via QR scan or manual entry. The companion app is the management surface; the keyboard is the daily-use surface.