Apple’s two-factor authentication and app-specific password implementation is bad. Let’s have a little tour.
How it works
The general idea behind Apple’s 2FA is sound if not perfect: instead of giving every crappy mail and calendar app you use your main password, you give it an app-specific password. To do this, you need to have two-factor authentication turned on. Apple’s two-factor authentication protocol doesn’t use TOTP or HOTP codes like pretty much everyone else—it uses your other Apple devices, with a fallback to SMS/voice code verification. In practice, so long as it doesn’t fallback to SMS, I’m kind of okay with Apple securely sending a 2FA code to another device. SMS is only really going to be used for people with one Apple device.
How many and what devices you can authorise to your account is another issue, but there’s a really tl;dr StackExchange answer about that particular matter.
How it doesn’t work
A fairly major problem: is almost impossible to know whether a password field asking for your Apple ID/iCloud password wants your actual password or an app-specific password. If you put in your actual password and it wants an app-specific password, or vice versa, it just says you put in a wrong password. Then if you do that again, because, say, you think you might have typed the app-specific password in wrong, that triggers the “you’ve forgotten your password” routine. Which revokes all existing app-specific passwords, so you now need to go generate new app-specific passwords on every device that needs them.
The problem with this is why an app is asking for your password is fairly unknown. If you use the stock Calendar app on macOS, it won’t ask you for your iCloud password. If you use a third-party calendar app like Fantastical or Busycal, you have to log in with an app-specific password. But on iOS, if you use Fantastical, it uses an iOS system call to just get your calendar information from the OS. This inconsistency doesn’t really seem well explained to users.
Another fun failure mode of Apple IDs: if you have a credit card tied to your Apple ID, to buy stuff from iTunes or the App Store or whatever, and that credit card number gets revoked, any iOS devices will start badgering you to log in to your Apple ID to change your credit card number. Which you may not be able to do until your credit card issue gives you a new credit card number. You also can’t download any apps during this period, even ones that are free and have no in-app purchases. Because Apple.
For any particular app-specific password, you can’t see whether it is actively being used. Other services like GitHub, Google, Fastmail and Twitter allow you to see what devices and external apps are connected to your account, when they were last used, from what IP address (with an estimated country etc.), and revoke access to any that you are no longer using. You can revoke Apple ID app-specific passwords, but there’s no information whether they are still active or not.
Another frustration with Apple ID’s app-specific password functionality is there is no scoping of access. One of the key benefits of an access delegation protocol like OAuth is you can scope access to your account. When you sign in to something with GitHub, you can choose whether to give it access to private or only public repositories, what particular organisational repos it can access (and the organisation admins can set that too, specifically forbidding users from granting access to private, organisation-owned code), and so on.
With Apple ID app-specific passwords, there is no scoping—it is all-or-nothing. Your mail app can see your mail, but it can also see your calendars, contacts and anything else your Apple ID gives it access to. Compare this to Fastmail: when you generate an app-specific password for a Fastmail account, you can specify you just want a password for SMTP, or just for IMAP, or for everything.
On iOS, developers have to release their apps through the App Store. On macOS, they are either having to release through the App Store, or with a binary signed through a certificate issued by Apple. Given this, it seems strange Apple doesn’t have a process for beefing up app-specific access delegation. Rather than a user having to go to the Apple ID site, log in, go through two-factor, then generate an app-specific password, why not just have the already signed app to request permission from the OS? You can still have app-specific passwords for users to be able to allow access to IMAP/SMTP/CalDAV/CardDAV etc. for unsigned apps, home-brewed utilities, but for the most common use case, the authentication process can be made a lot smoother. You then get the advantage that the user can log into a dashboard where it shows them a list of the actual apps that are using app-specific authentication keys, and you can monitor to make sure they are only making requests that match their functionality.
The security processes feels unloved at best, erratic and unpredictable at worst. It does not inspire trust, especially given the oodles of personal information hidden away in iCloud accounts. This is a shame, since Apple is one of the only big tech companies which does not make much, if any, of its money off exploiting private user data.
The frustration that the two-factor and app-specific password mode causes is likely to prompt even very security conscious users to turn them off because they are such a gigantic hassle. That’s bad security design.
Good security is mostly going to be a slightly worse experience than non-existent security—longer passwords take longer to type (and you basically now need a password manager), typing in 2FA codes is nobody’s idea of a fun time—but if the security process is so frustrating that people try and work around it, that’s really bad for user security. Once the user has decided that it is too frustrating to use your security process, you may have potentially lost them forever. They’ll just opt-out in the future, even if you improve your security process. That is why it is important to get it right.
There is a lot Apple does get right with security UX. This is not one of them.